我试图了解32位和64位处理器之间的对象大小差异.假设我有一个简单的课程
class MyClass
{
int x;
int y;
}
Run Code Online (Sandbox Code Playgroud)
所以在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
dtb*_*dtb 26
CLR可以根据需要随意在内存中布置对象.这是一个实现细节.您不应该依赖任何特定的布局.
您看到的差异是由于缺少TypeHandle字段,该字段也是CLR对象标头的一部分.另外,字段可以与字节边界对齐.
对象的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
另请参阅:深入了解.NET Framework内部以了解CLR如何创建运行时对象
同步块位于与对象指针的负偏移处.偏移0处的第一个字段是方法表指针,x64上的8个字节.所以在x86上它是SB + MT + X + Y = 4 + 4 + 4 + 4 = 16字节.同步块索引在x64中仍然是4个字节.但是对象头也参与了垃圾收集堆,在释放后充当链表中的节点.这需要一个后退和一个前向指针,每个8字节在x64中,因此在对象指针之前需要8个字节.8 + 8 + 4 + 4 = 24字节.
| 归档时间: |
|
| 查看次数: |
2787 次 |
| 最近记录: |