.NET高级调试 - 3.7对象检查
简介
在大多数调试会话中,首先需要检查的项目就是分析应用程序的状态。在确认程序的问题是某种无效状态造成的,我们便需要分析程序是如何变成无效状态的。那么在分析过程中,需要为我们深入了解对象的各种审查方法
内存转储
内存转储非常底层,是从内存地址上观察地址上的内容,常常使用d系列命令观察
对象的“类型显示存储于其表现形式中”从实现角度来看,它指的是MethodTable。这就也是对象互相引用的引用点。但是在Method Table之前,还有一个object header . 所以为什么说 object header 位于“负索引”的原因。因此要完整展示一个引用类型对象。需要address-0x4(64位程序需要-0x8) 。才是一个完整的内存布局。
托管对象转储
有时候直接把内存转储出来会很直观,但调试托管代码时,如果能将CLR对象以一种更加结构化和易阅的形式转储出来,会更加优雅。
引用类型转储
使用!dumpobj 命令来更加友好的转储出引用类型,更加一目了然。
Fields解释:
Field | Offset | Type | VT | Attr | Value | Nmae |
---|---|---|---|---|---|---|
这个域的元数据 | 偏移量 | 类型 | 为1表示是值类型,为0代表是引用类型 | 对象的属性 | 域的值 | 域的名字 |
如果值类型数据作为引用类型的一部分,那么它也会被视为引用类型分配在托管堆中。那么如何查看值类型的内容呢?
使用!dumpvc 命令即可查看。
internal class Program
{
static void Main(string[] args)
{
var s = new MyStruct(100, 101, 102);
var o = new
{
x = s
};
Debugger.Break();
}
}
public struct MyStruct
{
public MyStruct(int x,int y,int z)
{
this.x= x; this.y = y; this.z = z;
}
public int x;
public int y;
public int z;
}
值类型转储
如果是值类型,使用!dumpobj会显示一个错误,我们可以利用此特性来判断一个对象是引用类型还是值类型
由于值类型解释其自身,我们直接使用d命令即可
数组的转储
可以使用!dumparray 命令来转储数组
值类型数组
数组的内存结构如下
static void Main(string[] args)
{
int[] intArr = { 10, 11, 12, 13, 14, 15, 16, 17 };
Debugger.Break();
}
可以看到内存布局与代码一一对应
引用类型数组
static void Main(string[] args)
{
string[] stringArr = { "10", "11","12","13","14","15" };
Debugger.Break();
}