据我所知,所有.NET对象实例都以一个8字节的“对象头”开头:一个同步块(指向SynchTableEntry表的4字节指针)和一个类型句柄(指向类型方法表的4字节指针)。
我在VS 2010 RC(CLR 4.0)调试器内存窗口中没有看到这一点。
这是一个简单的类,它将生成一个16字节的实例,而不是对象标题。
class Program
{
short myInt = 2; // 4 bytes
long myLong = 3; // 8 bytes
string myString = "aString"; // 4 byte object reference
// 16 byte instance
static void Main(string[] args)
{
new Program();
return;
}
}
SOS对象转储告诉我总对象大小为24个字节。那讲得通。我的16字节实例加上一个8字节的对象标题。
!DumpObj 0205b660 Name: Offset_Test.Program MethodTable: 000d383c EEClass: 000d13f8 Size: 24(0x18) bytes File: C:\Users\Bob\Desktop\Offset_Test\Offset_Test\bin\Debug\Offset_Test.exe Fields: MT Field Offset Type VT Attr Value Name 632020fc 4000001 10 System.Int16 1 instance 2 myInt 632050d8 4000002 4 System.Int64 1 instance 3 myLong 631fd2b8 4000003 c System.String 0 instance 0205b678 myString
这是原始记忆:
0x0205B660 000d383c 00000003 00000000 0205b678 00000002 ...
以下是一些注释:
offset 0 000d383c ;TypeHandle (pointer to MethodTable), 4 bytes offset 4 00000003 00000000 ;myLong, 8 bytes offset 12 0205b678 ;myString, 4 byte reference to address of "myString" on GC Heap offset 16 00000002 ;myInt, 4 bytes
我的对象开始地址0x0205B660。但我只能占它的20个字节,类型句柄和实例字段。没有同步块指针的迹象。对象大小报告为24个字节,但调试器显示它只占用20个字节的内存。
我正在阅读Drill Into .NET Framework Internals to See How the CLR Creates Runtime Objects,并期望我的对象的前4个字节是一个归零的同步块指针,如该文章的图8所示。当然,这是一篇关于CLR 1.1的文章。
我只是想知道我所看到的内容和早期文章报告的内容之间的区别是调试器的对象布局显示的更改,还是CLR在1.1之后的版本中布局对象的方式。
无论如何,任何人都能解释我丢失的4个字节吗?
答案 0 :(得分:8)
我相信同步块在内存中的对象指针“后面”。这样,引用变量直接指向方法表。因此,对于地址为0x0205B660的对象,同步块将位于地址0x0205B65C。