找出对象在.NET中使用了多少内存的最简单方法是什么?

时间:2008-09-30 20:46:30

标签: c# .net memory

找出对象在.NET中使用了多少内存的最简单方法是什么?

最好不必诉诸第三方工具。 Marshal.SizeOf或sizeof运算符看起来很有用,但只适用于有限范围的类型。

一些相关帖子:

3 个答案:

答案 0 :(得分:2)

在这里提问并回答:Determine how much memory a class uses?

快速摘要是,如果您不想使用工具,则需要使用.NET Profiling API

Profiling API非常强大,但我不认为它会被任何想象力限制为“简单”,所以我强烈建议使用内存分析工具 - 有一些免费的,还有一些非常昂贵的商业产品(特别是JetBrains dotTrace)非常好。

答案 1 :(得分:0)

您也可以这样做:

int startMem = GC.GetTotalMemory(true);
YourClass c = new YourClass();
int endMem = GC.GetTotalMemory(true);
int usedMeme = endMem - startMem;

答案 2 :(得分:0)

由于.NET的垃圾收集性质,测量实际使用的内存有点困难。例如,如果要测量类实例的大小,是否包含实例指向的实例使用的内存?

如果答案为否,请加上所有字段的大小: 使用反射,遍历类的所有成员;将Marshal.Sizeof(member.Type)用于任何typeof(ValueType).IsAssignableFrom(member.Type) - 它测量原始类型和结构,所有这些都存在于类的实例分配中。每个引用类型(任何不可分配给valuetype的引用)都将采用IntPtr.Size。有一些令人厌恶的例外情况,但它可能适合你。

如果答案是肯定的,则会出现严重问题。多个内容可以引用单个实例,因此如果“a”和“b”都指向“c”,则RecursiveSizeOf(a) + RecursiveSizeOf(b)将大于SimpleSizeOf(a) + SimpleSizeOf(b) + SimpleSizeOf(c)

更糟糕的是,递归测量可能会导致您忽略循环引用,或者导致您无法测量的对象 - 例如,如果某个类引用了互斥锁,则该互斥锁可能指向拥有它的线程。该线程可能指向其所有局部变量,这些变量指向一些C#框架结构......您最终可能会测量整个程序。

可能有助于理解像C#这样的垃圾收集语言在描述对象和内存单元之间的区别方式上有点“模糊”(从完全非技术意义上说)。这是Marshal缓解的很多内容 - 编组规则确保您正在编组(或测量)的结构具有明确定义的内存布局,因此具有明确定义的大小。在这种情况下,如果您打算使用Marhsal.SizeOf(),则应使用定义良好的可编组结构。

另一种选择是序列化。这不会具体告诉您正在使用多少内存,但它会让您对对象的大小有一个相对的了解。但同样,为了序列化事物,它们必须具有明确定义的布局(因此具有明确定义的大小) - 您可以通过使类适当地序列化来实现。

如果上述任何选项对您有吸引力,我可以发布实施示例。