【发布时间】:2014-11-15 23:39:26
【问题描述】:
所有 .NET 类都将同步块和类型指针存储为它们的实例的一部分。这些在 32 位进程中总共占用 8 个字节,在 64 位进程中占用 16 个字节。但是,空类型实例的对象大小分别为 12 和 24 字节。
我看到一些文章说这是对齐问题,但是由于同步块和类型句柄是指针大小的,我不明白为什么需要添加任何填充。
其他文章说垃圾收集器需要它,但是它对开销有什么作用?它不能在那里存储任何东西,因为如果类型具有实例字段,则实际上会使用额外的空间。垃圾收集器是否在对象终结后的某个时间和在它被释放之前对该内存做一些事情,它需要一个地方来放置一些东西(可能是一个指针)?
以下是我读过的一些关于空字体大小的文章:
Performance Considerations of Class Design and General Coding in .NET:
如果您创建了一个没有字段的对象并在调试器中查看它,您会注意到它的大小实际上是 12 个字节,而不是 8 个。对于 64 位进程,该对象将是 24 个字节。这是因为最小尺寸是基于对齐的。值得庆幸的是,这个“额外”的 4 字节空间将被一个字段使用。
“最小”大小分别为 12 字节和 24 字节。换句话说,你不能有一个只是开销的类型。请注意“Empty”类如何占用与创建 Object 实例相同的大小……实际上有一些空闲空间,因为 CLR 不喜欢对没有数据的对象进行操作。
Drill Into .NET Framework Internals to See How the CLR Creates Runtime Objects:
如前所述,当前的 GC 实现需要一个至少 12 字节的对象实例。如果一个类没有定义任何实例字段,它将携带 4 个字节的开销。剩下的 8 个字节将被 Object Header(可能包含一个 syncblk 编号)和 TypeHandle 占用。
【问题讨论】:
-
“空类型实例的对象大小为 12 和 24 字节” - 你在某处读过这个吗?
-
对齐是一个非常重要的处理器实现细节。它提供了 .NET 内存模型的基本保证。原子性很重要,尤其是对于对象引用。没有它,你就无法编写线程代码。
-
@dcastro 我编辑了我的问题,包括对我读过的一些关于空字体大小的文章的引用。
-
@HansPassant 但是类型/同步块指针的 8 和 16 字节已经对齐。我不确定 12 和 24 字节大小如何有助于对齐。
-
对。但是 8 已经是 4 的倍数。而 16 已经是 8 的倍数。