了解32位与64位之间的CLR对象大小

时间:2010-09-28 17:03:41

标签: .net windbg sos

我试图了解32位和64位处理器之间的对象大小差异。假设我有一个简单的类

class MyClass   
{  
    int x;  
    int y;  
}  

因此在32位机器上,整数是4个字节。如果我将Syncblock添加到其中(另外4个字节),则对象大小将为12个字节。为什么显示16个字节?

0:000> !do 0x029d8b98  
Name: ConsoleApplication1.Program+MyClass  
MethodTable: 000e33b0  
EEClass: 000e149c  
Size: 16(0x10) bytes  
 (C:\MyTemp\ConsoleApplication1\ConsoleApplication1\bin\x86\Debug\ConsoleApplication1.exe)  
Fields:  
      MT    Field   Offset                 Type VT     Attr    Value Name  
71972d70  4000003        4         System.Int32  1 instance        0 x  
71972d70  4000004        8         System.Int32  1 instance        0 y  

在64位机器上,一个整数仍然是4个字节,唯一改变的是Syncblock将是8个字节(因为指针是64位机器上的8个字节)。这意味着对象大小将是16个字节。为什么显示24个字节?

0:000> !do 0x00000000028f3c90  
Name: ConsoleApplication1.Program+MyClass  
MethodTable: 000007ff00043af8  
EEClass: 000007ff00182408  
Size: 24(0x18) bytes  
 (C:\MyTemp\ConsoleApplication1\ConsoleApplication1\bin\Debug\ConsoleApplication1.exe)  
Fields:  
              MT    Field   Offset                 Type VT     Attr            Value Name  
000007fef4edd998  4000003        8         System.Int32  1 instance                0 x  
000007fef4edd998  4000004        c         System.Int32  1 instance                0 y  

4 个答案:

答案 0 :(得分:25)

CLR可以随意在内存中布置对象。这是一个实现细节。您不应该依赖任何特定的布局。

您看到的差异是由于缺少TypeHandle字段,该字段也是CLR对象标头的一部分。此外,字段可以与字节边界对齐。


来自Advanced .Net Debugging - CLR Object’s Internal Structure

  

对象的CLR内部结构是:

     

[DWORD:SyncBlock] [DWORD:MethodTable指针] [DWORD:引用类型指针] ... [值类型字段的值] ...

     

对象标题: [DWORD:SyncBlock]
  对象指针: [DWORD:MethodTable指针] [DWORD:引用类型指针] ... [值类型字段的值] ...

     

每个对象前面都有一个ObjHeader(负偏移)。 ObjHeader有一个SyncBlock的索引。


所以你的对象很可能是这样的:

x86 :(对齐为8个字节)

  Syncblk     TypeHandle       X            Y
------------,------------|------------,------------|
                         8                         16

x64 :(对齐为8个字节)

         Syncblk                  TypeHandle             X            Y
-------------------------|-------------------------|------------,------------|
                         8                         16                        24

另请参阅:Drill Into .NET Framework Internals to See How the CLR Creates Runtime Objects

答案 1 :(得分:7)

同步块位于距对象指针的负偏移处。偏移0处的第一个字段是方法表指针,x64上的8个字节。所以在x86上它是SB + MT + X + Y = 4 + 4 + 4 + 4 = 16字节。同步块索引在x64中仍然是4个字节。但是对象头也参与了垃圾收集堆,在释放后充当链表中的节点。这需要一个后退和一个前向指针,每个8字节在x64中,因此在对象指针之前需要8个字节。 8 + 8 + 4 + 4 = 24字节。

答案 2 :(得分:0)

对象在成员变量之外有一些开销。在.NET的32位实现中,分配开销似乎是12个字节。我记得,它在64位运行时中是16个字节。

此外,对象分配在下一个8字节边界上对齐。

答案 3 :(得分:0)

对我来说,任何对象都应该有一些指向其类的指针。这会占你额外的4或8个字节。

但是,对象的布局实际上是一个实现的东西。如果您关心布局,那么有一些属性可以明确告诉.net您希望成员定位的位置和方式。查看StructLayoutAttribute

相关问题