c# 4.0 - c#对象大小开销

本文关键字:开销 对象 | 更新日期: 2023-09-27 17:51:19

我正在研究内存消耗应用程序的优化。与此相关,我对c#引用类型的大小开销有疑问。

c#对象消耗和它的字段一样多的字节,加上一些额外的管理开销。我认为对于不同的。net版本和实现,管理开销可能是不同的。

你知道c#对象(c# 4.0和Windows 7和8环境)的管理开销的大小(或最大大小,如果开销是可变的)吗?

管理开销在32位和64位。net运行时之间有区别吗?

c# 4.0 - c#对象大小开销

通常,GC分配的每个对象有8或12个字节的开销。在32位运行时,同步块有4个字节,类型句柄有4个字节,在64位运行时有8个字节。有关详细信息,请参阅深入。net框架内部查看CLR如何在MSDN杂志上创建运行时对象的"ObjectInstance"部分。

请注意,实际的引用在32位或64位。net运行时也会改变。

也可以为类型填充以适应地址边界,尽管这在很大程度上取决于所讨论的类型。这也可能导致对象之间的"空白空间",但这取决于运行时(主要是,尽管您可以使用StructLayoutAttribute来影响它)来确定何时以及如何对齐数据。

网上有一篇文章题为"。net对象的真相及在应用域之间的共享";其中显示了一些转子源代码和一些实验结果的对象,并通过一个普通的指针在应用程序域之间共享它们。

http://geekswithblogs.net/akraus1/archive/2012/07/25/150301.aspx

  • 所有32位CLR版本的12个字节
  • 所有64位CLR版本的24字节

你可以很容易地通过向数组中添加数百万个对象(N)来测试这一点。因为指针的大小是已知的,所以可以通过将该值除以n来计算对象的大小。

var initial = GC.GetTotalMemory(true);
const int N = 10 * 1000 * 1000;
var arr = new object[N];
for (int i = 0; i < N; i++)
{
    arr[i] = new object();
}
var ObjSize = (GC.GetTotalMemory(false) - initial - N * IntPtr.Size) / N;

在你的。net平台上得到一个近似值。

对象大小的定义实际上是为了允许GC对最小对象大小进行假设。

'sscli20'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))

例如,对于32位,这意味着最小对象大小为12字节,这确实留下了4字节的漏洞。对于空对象,这个洞是空的,但是如果你在空类中添加int,那么它就会被填充,对象的大小保持在12个字节。

对象的开销有两种:

  • 处理对象的内部数据。
  • 数据成员之间的填充。

内部数据是两个指针,因此在32位应用程序中是8字节,在64位应用程序中是16字节。

填充数据成员,使它们从偶数地址边界开始。例如,如果在类中有一个byte和一个int,则byte可能用三个未使用的字节填充,以便int从下一个机器字边界开始。

类的布局是由JIT编译器根据系统的体系结构决定的(在不同的框架版本之间可能会有所不同),所以c#编译器是不知道的。