一个朴素的类型系统会将对象存储为指向其类型的指针(它包含许多有用的信息,如vtable、对象大小等)。然后是它的数据。如果.Net具有这样的类型系统,则object在32位系统上将占用4个字节,而在64位系统上将占用8个字节。
We can see that it doesn't。对象开销是两个指针大小,另外,还有一个指针大小的“最小”大小。
那么object在幕后到底存储了什么呢?
发布于 2011-04-06 11:17:21
是的,看起来就是这样。“类型句柄”,又名“方法表指针”位于偏移量0处,对象数据位于偏移量4处。在偏移量-4处有一个额外的字段,名为“syncblock”。它存在的原因是,当对象空间未被使用时,它还会参与垃圾收集堆,这是一个需要两个指针的空闲块的双向链表。不要浪费,同步块有几种用途,比如存储锁状态,存储哈希码,当需要存储太多内容时存储指向显式同步块的指针。
最小的对象是一个装箱的字节,4+4+1=9个字节。但是GC堆的分配粒度是4字节,因此您将得到4,12字节的下一个倍数。
这在Visual Studio中的调试器中非常明显。您可以在this answer中找到提示。
发布于 2011-04-06 11:08:38
(这一切都来自Microsoft Shared Source CLI;它有CLR的源代码。)
如果你看一下clr\src\vm\object.h,你会看到:
// The generational GC requires that every object be at least 12 bytes in size.
#define MIN_OBJECT_SIZE (2*sizeof(BYTE*) + sizeof(ObjHeader))这是非常不言而喻的。此外,在clr\src\vm\gcscan.cpp中,您可以看到如下语句
_ASSERTE(g_pObjectClass->GetBaseSize() == MIN_OBJECT_SIZE);或
_ASSERTE(totalSize < totalSize + MIN_OBJECT_SIZE);我想这就解释了为什么你会看到意想不到的物体大小。:)
更新:
@Hans在sync块上有一个很好的观点;我只想指出一个微妙之处,在object.h中再次记录下来
/* Object
*
* This is the underlying base on which objects are built. The MethodTable
* pointer and the sync block index live here. The sync block index is actually
* at a negative offset to the instance. See syncblk.h for details.
*/
class Object
{
protected:
MethodTable* m_pMethTab;
//No other fields shown here!
};请注意这一部分:
对于实例,同步块索引实际上处于负偏移量(
)。
显然,sync块实际上并不遵循方法表(正如Hans提到的那样),但它位于方法表之前--因此它不是对象的“正常”部分(因为没有更好的词)。
https://stackoverflow.com/questions/5561008
复制相似问题