16

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

class MyClass   
{  
    int x;  
    int y;  
}  

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

0:000> !do 0x029d8b98  
名称:ConsoleApplication1.Program+MyClass  
方法表:000e33b0  
EE类:000e149c  
大小:16(0x10)字节  
 (C:\MyTemp\ConsoleApplication1\ConsoleApplication1\bin\x86\Debug\ConsoleApplication1.exe)  
领域:  
      MT 字段偏移类型 VT Attr 值名称  
71972d70 4000003 4 System.Int32 1 实例 0 x  
71972d70 4000004 8 System.Int32 1 实例 0 是  

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

0:000> !do 0x00000000028f3c90  
名称:ConsoleApplication1.Program+MyClass  
方法表:000007ff00043af8  
EE类:000007ff00182408  
大小:24(0x18)字节  
 (C:\MyTemp\ConsoleApplication1\ConsoleApplication1\bin\Debug\ConsoleApplication1.exe)  
领域:  
              MT 字段偏移类型 VT Attr 值名称  
000007fef4edd998 4000003 8 System.Int32 1 实例 0 x  
000007fef4edd998 4000004 c System.Int32 1 实例 0 y  
4

4 回答 4

26

CLR 可以根据需要在内存中自由布局对象。这是一个实现细节。您不应该依赖任何特定的布局。

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


来自高级 .Net 调试 - CLR 对象的内部结构

一个对象的 CLR 内部结构是:

[DWORD: SyncBlock][DWORD: MethodTable Pointer][DWORD: 引用类型指针]…[值类型字段的值]…</p>

对象头: [DWORD:SyncBlock]
对象指针: [DWORD:方法表指针][DWORD:引用类型指针]…[值类型字段的值]…</p>

每个 Object 前面都有一个 ObjHeader(在负偏移处)。ObjHeader 有一个 SyncBlock 的索引。


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

x86:(对齐到 8 个字节)

  Syncblk 类型手柄 XY
------------,------------|------------,------------ -|
                         8 16

x64:(对齐到 8 个字节)

         Syncblk 类型手柄 XY
-------------------------|------------------------ -|------------,------------|
                         8 16 24

另请参阅:深入了解 .NET Framework 内部结构以了解 CLR 如何创建运行时对象

于 2010-09-28T17:06:28.957 回答
9

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

于 2010-09-28T18:05:39.773 回答
0

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

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

于 2010-09-28T17:09:50.113 回答
0

在我看来,任何对象都应该有某种指向其类的指针。这将占您额外的 4 或 8 个字节。

不过,对象的布局实际上是一种实现。如果您关心布局,则有一些属性旨在明确告诉 .net 您希望成员定位的位置和方式。查看StructLayoutAttribute

于 2010-09-28T17:11:56.387 回答