C#对象大小开销

时间:2013-01-11 20:51:05

标签: c# c#-4.0

我正致力于优化内存消耗应用程序。关于这一点,我对C#引用类型大小开销有疑问。

C#对象消耗与其字段一样多的字节,加上一些附加管理 开销即可。我认为不同的.NET版本和实现的管理开销可能不同。

您是否知道C#对象(C#4.0和Windows 7和8环境)的管理开销的大小(如果开销是可变的,则是最大大小)?

32位或64位.NET运行时的管理开销是否不同?

4 个答案:

答案 0 :(得分:15)

通常,GC分配的每个对象有8或12字节的开销。 syncblk有4个字节,32位运行时有4个字节,64位运行时有8个字节。有关详细信息,请参阅MSDN杂志上Drill Into .NET Framework Internals to See How the CLR Creates Runtime Objects的“ObjectInstance”部分。

请注意,实际引用也会在32位或64位.NET运行时更改。

此外,类型的填充可能适合地址边界,但这很大程度上取决于所讨论的类型。这也可能导致对象之间出现“空白空间”,但是由运行时(主要是,虽然您可以使用StructLayoutAttribute影响它)来确定数据的对齐时间和方式。

答案 1 :(得分:6)

在线有一篇文章标题为“关于.NET对象及在AppDomains之间共享的真相”,其中显示了一些转子源代码以及一些实验对象并通过普通指针在appdomains之间共享它们的结果。

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

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

通过向数组中添加数百万个对象(N),您可以非常轻松地进行测试。由于指针大小已知,您可以通过除以

的值来计算对象大小
var intial = 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 = (initial-GC.GetTotalMemory(false)-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位这意味着minmum对象大小为12个字节,这确实留下了4个字节的漏洞。对于空对象,此孔为空,但如果添加例如一个int到你的空类然后它被填充,对象大小保持12个字节。

答案 2 :(得分:4)

对象有两种类型的开销:

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

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

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

类的布局由JIT编译器根据系统的体系结构确定(并且可能因框架版本而异),因此C#编译器不知道。

答案 3 :(得分:0)

我测试过。在我的测试中,空对象占用 24 字节,但包括对象中的前 8 字节数据。 IE。空物体尺寸:24B。具有 2 个整数属性的对象:24B。具有 3 个整数属性的对象:32B