我正致力于优化内存消耗应用程序。关于这一点,我对C#引用类型大小开销有疑问。
C#对象消耗与其字段一样多的字节,加上一些附加管理 开销即可。我认为不同的.NET版本和实现的管理开销可能不同。
您是否知道C#对象(C#4.0和Windows 7和8环境)的管理开销的大小(如果开销是可变的,则是最大大小)?
32位或64位.NET运行时的管理开销是否不同?
答案 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
通过向数组中添加数百万个对象(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个字节。
填充数据成员,使它们从偶数地址边界开始。例如,如果您在类中有byte
和int
,那么byte
可能会填充三个未使用的字节,以便int
从下一个机器字边界开始
类的布局由JIT编译器根据系统的体系结构确定(并且可能因框架版本而异),因此C#编译器不知道。
答案 3 :(得分:0)
我测试过。在我的测试中,空对象占用 24 字节,但包括对象中的前 8 字节数据。 IE。空物体尺寸:24B。具有 2 个整数属性的对象:24B。具有 3 个整数属性的对象:32B