.Net 2.0内存对象布局详析及与1.1变化比较

写本文主要两个目的,一个是解析下2.0下的对象在内存里面究尽是个什么样子的布局,使用windbgsosshow下内存里面的bit是如何组织其来的。另外一个就是比较下和.Net Framework 1.1你面的内存布局有什么区别,修正下“Drill Into .NET Framework Internals to See How the CLR Creates Runtime Objects”里面的很多说法在Framework 2.0下面的不同的地方。

好久以前整的东西,这会给记录下来。表笑话,现在都

 

首先找个小的C#的演示程序:

namespace CLRLayoutTest2._0

{

    class Program

    {

        static int TestStaticFields = 1221119;

        static object TestStaticObject = new object();

 

        static string TestStaticMethod()

        {

            return "Test Static Method";

        }

 

        static void Main(string[] args)

        {

            Program a = new Program();

            a.Test();

            System.Console.ReadLine();

        }

 

        public void Test()

        {

            int i = 2;

            object testObject = (object)i;

 

            System.Console.WriteLine(testObject.ToString());

            System.Console.WriteLine(TestStaticFields.ToString());

 

        }

    }

}

 

好,设置好在.Net Framework 2.0的环境下给编译了。然后设置好windbg的调试环境,接着给attach上去:

0:000> !dso

OS Thread Id: 0x79c (0)

ESP/REG  Object   Name

0012f3c4 013f37b8 Microsoft.Win32.SafeHandles.SafeFileHandle

0012f3d4 013f37b8 Microsoft.Win32.SafeHandles.SafeFileHandle

0012f408 013f3854 System.Byte[]

0012f40c 013f37cc System.IO.__ConsoleStream

0012f430 013f37fc System.IO.StreamReader

0012f434 013f37fc System.IO.StreamReader

0012f438 013f16e8 CLRLayoutTest2._0.Program

0012f448 013f37fc System.IO.StreamReader

0012f44c 013f3b70 System.IO.TextReader+SyncTextReader

0012f450 013f16e8 CLRLayoutTest2._0.Program

0012f460 013f3b70 System.IO.TextReader+SyncTextReader

0012f464 013f16e8 CLRLayoutTest2._0.Program

0012f46c 013f16e8 CLRLayoutTest2._0.Program

0012f478 013f16cc System.Object[]    (System.String[])

0012f534 013f16cc System.Object[]    (System.String[])

0012f6e0 013f16cc System.Object[]    (System.String[])

0012f708 013f16cc System.Object[]    (System.String[])

 

看到咱的Program了,接着就看看013f16e8里面都有些啥呢,

0:000> !objsize 013f16e8

sizeof(013f16e8) = 12 (0xc) bytes (CLRLayoutTest2._0.Program)

 

好吧,12个字节,lesgo,查看memory

013f16e8 0000000000a83060 7910229000000000

013f16f8 0000000000000002 00000000790fd0f0

 

给标出来的部分,就是CLRLayoutTest2._0.Program这个type的一个instance object在内存里面的内容。

这个地方,稍微再说说一个object instance在内存你面的结构,在以前的文章里面有详细说过这个东西的。一个instance的前2个字节,保存的是SyncBlk,这个是和同步相关的东西,其实现原理和lock是一样的,flier曾经写过文章讲SyncBlk的实现原理和过程,感兴趣的可以去看看。接着下来的2个字节,保存的就是type handle,也就是我们经常说的obj ref,对一个对象的引用其实就是指到这个的方的。这个例子里面,显示的是00a83060

 

我们可以来验证下:

0:000> !do 013f16e8

Name: CLRLayoutTest2._0.Program

MethodTable: 00a83060

EEClass: 00a811f4

Size: 12(0xc) bytes

 (E:/myProject/CLRLayoutTest2.0/CLRLayoutTest2.0/bin/Debug/CLRLayoutTest2.0.exe)

Fields:

      MT    Field   Offset            Type    Attr   Value Name

79102290  4000001       1c    System.Int32  static  1221119 TestStaticFields

790fd0f0  4000002        4   System.Object   static 013f16dc TestStaticObject

 

可以看到,这个对象的MethodTable: 00a83060,就是在object instance的数据空间的第5个字节开始起,四个字节存放的地方。79102290这个内存地址show的东西,就是这个typeinstanceinstance data。可以在上面的Fields区域里面看到,指类型变量,不包括ref type的数据的MT,都会在这个的方给show出来。0000000000000002,一个四个字节大小的空间,正是一个System.Int32的大小,

 

一个object在内存你面主要的东西,包括object instance,以及保存这个object重要结构的MethodTable,还有保存和object对应的typeEEClass。这三个东西,构成了内存里面一个object的主要内容。接下来看看主要数据结构MethodTable及其变化。

 

0:000> !dumpmt -md 00a83060

EEClass: 00a811f4

Module: 00a82c3c

Name: CLRLayoutTest2._0.Program

mdToken: 02000002  (E:/myProject/CLRLayoutTest2.0/CLRLayoutTest2.0/bin/Debug/CLRLayoutTest2.0.exe)

BaseSize: 0xc

ComponentSize: 0x0

Number of IFaces in IFaceMap: 0

Slots in VTable: 9

--------------------------------------

MethodDesc Table

   Entry MethodDesc      JIT Name

79371278   7914b928   PreJIT System.Object.ToString()

7936b3b0   7914b930   PreJIT System.Object.Equals(System.Object)

7936b3d0   7914b948   PreJIT System.Object.GetHashCode()

793624d0   7914b950   PreJIT System.Object.Finalize()

00a8c011   00a83038     NONE CLRLayoutTest2._0.Program.TestStaticMethod()

00db00c0   00a83040      JIT CLRLayoutTest2._0.Program.Main(System.String[])

00db0148   00a83048      JIT CLRLayoutTest2._0.Program.Test()

00db0118   00a83050      JIT CLRLayoutTest2._0.Program..ctor()

00db0070   00a83058      JIT CLRLayoutTest2._0.Program..cctor()

 

上面是SOS解析好了内存之后列出的内存结构,使用quad Hex格式显式出来的,可能不是很好辨认,下面换一种内存的现示格式,咱看看内存里面MethodTable是如何组织的:

00a83050 39030004 00000007 39040005 00200008

00a83060 00040000 0000000c 00090002 00000004

00a83070 790fd0f0 00a82c3c 00a830b0 00a811f4

00a83080 00000000 00000000 79371278 7936b3b0

00a83090 7936b3d0 793624d0 00a8c011 00db00c0

00a830a0 00db0148 00db0118 00db0070 00000000

00a830b0 00000080 00000000 00000000 00000000

首先,从-12byte开始的的方看起,这个地方的数据是00000007 39040005 00200008,你面保存了和GC相关的信息。00a83060MT的地址。

00040000占用四个字节,在定义的时候被定义成为一个DWORD,表示的是一个flag。这个flag的低位的那个word,也就是0004,表示的含义是arraystring type在这个component里面的总和。我也不晓的怎么就算了个4出来。下面的一个0000000c表示的是这个class被分配到heap上面的时候的大小。这个大小只是计算了instance data的大小,其余的和clr相关的数据结构的大小并没有包含进去,从上面也可以看到。

00090002,这个需要分成四个部分来解释含义:0009000200表示的是另外一个重要的标志位。其各个enum的值含义如下:

    enum

    {

        enum_flag2_MarshaledByRef                       = 0x0001,

        enum_flag2_NoSecurityProperties             = 0x0002,

        enum_flag2_HasGenericsStaticsInfo            = 0x0004,

        enum_flag2_MayNeedRestore                 = 0x0008,

        enum_flag2_UNUSED                   = 0x0010,

        enum_flag2_IsZapped                    = 0x0020,

        enum_flag2_IsDynamicStatics               = 0x0040,

        enum_flag2_FixedAddressVTStatics           = 0x0080,

        enum_flag2_GenericsMask                 = 0x0300,

        enum_flag2_GenericsMask_NonGeneric       = 0x0000,

        enum_flag2_GenericsMask_CanonInst        = 0x0100,

        enum_flag2_GenericsMask_NonCanonInst   = 0x0200,

        enum_flag2_GenericsMask_TypicalInst       = 0x0300,

        enum_flag2_ClassPreInited                 = 0x0400,

        enum_flag2_IsAsyncPin                  = 0x0800,

        enum_flag2_ContainsGenericVariables        = 0x1000, 

        enum_flag2_IsInterface                    = 0x2000,

        enum_flag2_HasDispatchMap              = 0x4000,

        enum_flag2_HasVariance                             = 0x8000,

    };

09表示的是有9个方法。00表示虚方法0个,后面表示有2个接口。这个接口,应该是从父类继承过来的。

这里出现的第一个变化,是在.Net Framework 1.1中,0000000c之后出现的应该是EEClass的地址。这里确变成了一段标识位。00000004的含义,推测不出来

接下来的790fd0f0,表示的是static ref类型的地址。它的值,存放在013f16dc的地方。00a82c3cmodule的地址。00a811f4保存的是EEClass的地址。

00000000 00000000表示numbers of vtable slots,这里没有。

下面的79371278 7936b3b0 7936b3d0 793624d0 00a8c011 00db00c0 00db0148 00db0118 00db0070,表示的是9个方法的Entry入口。

这里还可以看到与1.1里面的一个变化,就是System.Object的几个基本方法的入口地址的顺序给改变了。

 

因为程序里面没有涉及到static strinterface的定义,所以后面的内存地址中就没数据了。

 

最后看看EEClass的数据结构:

 

0:000> !dumpclass 00a811f4

Class Name: CLRLayoutTest2._0.Program

mdToken: 02000002 (E:/myProject/CLRLayoutTest2.0/CLRLayoutTest2.0/bin/Debug/CLRLayoutTest2.0.exe)

Parent Class: 790fd08c

Module: 00a82c3c

Method Table: 00a83060

Vtable Slots: 4

Total Method Slots: 9

Class Attributes: 100000 

NumInstanceFields: 0

NumStaticFields: 2

      MT    FieldOffset                 Type VT     Attr    Value Name

79102290  4000001    1c    System.Int32  1   static  1221119 TestStaticFields

790fd0f0  4000002     4  System.Object     0   static 013f16dc TestStaticObject

 

Show下对应的地址空间里面的内容:

00a811f4       00000000      00a82c3c       02000002       00a83060

00a81204       00070008      00000012      00010002      00000000

00a81214       00000000      ffffffff          ffffffff          00000000

00a81224       00a83010       00100000      02000100      00000000

 

最开始的00000000表示parentEEClass的地址。这里不是从别的Class继承过来的,所以是空的。00a82c3cmodule的地址。02000002分成四段来解释,分别表示number of interfaces,number of instance fields,number of staticfieldsnumber of dumplicate solts。解释的顺序是0002020000a83060是一个往回到MethodTable的连接,这样可以方便程序往回找。下面的两个dword,分别是EEClass里面不同类型的Fields的数量。

 

基本的结构就是这些,其实还有许多地方之间有关系的没有给发掘出来。恩,还有许多不准确的地方,以后慢慢修改。这玩意太痿琐了,MS随便变一下,也不给个文档,靠自个一个一个字节的扒拉太痛苦鸟。-_-

 

Wednesday, October 15, 2008 12:01:11 PM

First post at  sscli.cnblogs.com

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值