叫我安不理

.NET高级调试 - 3.7对象检查

简介

在大多数调试会话中,首先需要检查的项目就是分析应用程序的状态。在确认程序的问题是某种无效状态造成的,我们便需要分析程序是如何变成无效状态的。那么在分析过程中,需要为我们深入了解对象的各种审查方法

内存转储

内存转储非常底层,是从内存地址上观察地址上的内容,常常使用d系列命令观察
image
image

对象的“类型显示存储于其表现形式中”从实现角度来看,它指的是MethodTable。这就也是对象互相引用的引用点。但是在Method Table之前,还有一个object header . 所以为什么说 object header 位于“负索引”的原因。因此要完整展示一个引用类型对象。需要address-0x4(64位程序需要-0x8) 。才是一个完整的内存布局。

托管对象转储

有时候直接把内存转储出来会很直观,但调试托管代码时,如果能将CLR对象以一种更加结构化和易阅的形式转储出来,会更加优雅。

引用类型转储

使用!dumpobj 命令来更加友好的转储出引用类型,更加一目了然。
image

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;
    }

image

值类型转储

如果是值类型,使用!dumpobj会显示一个错误,我们可以利用此特性来判断一个对象是引用类型还是值类型
image

由于值类型解释其自身,我们直接使用d命令即可
image
image

数组的转储

可以使用!dumparray 命令来转储数组
image

值类型数组

数组的内存结构如下
image

        static void Main(string[] args)
        {
            int[] intArr = { 10, 11, 12, 13, 14, 15, 16, 17 };

            Debugger.Break();
        }

image

可以看到内存布局与代码一一对应

引用类型数组

image

        static void Main(string[] args)
        {
            string[] stringArr = { "10", "11","12","13","14","15" };
            Debugger.Break();
        }

image

总结

image

posted on 2024-10-08 13:49  叫我安不理  阅读(98)  评论(0编辑  收藏  举报

导航