我试图了解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
答案 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。