C#/ .NET对象使用多少内存?

时间:2009-01-08 23:00:47

标签: c# .net object memory profiling

我正在开发一个目前已创建数百个对象的应用程序。

是否可以确定(或近似)对象(类实例)分配的内存?

9 个答案:

答案 0 :(得分:39)

您可以使用像

这样的内存分析器

.NET Memory Profiler(http://memprofiler.com/

CLR Profiler(免费)(http://clrprofiler.codeplex.com/

答案 1 :(得分:37)

粗略的方式可能是这种情况,你想知道特定对象发生的事情

// Measure starting point memory use
GC_MemoryStart = System.GC.GetTotalMemory(true);

// Allocate a new byte array of 20000 elements (about 20000 bytes)
MyByteArray = new byte[20000];

// Obtain measurements after creating the new byte[]
GC_MemoryEnd = System.GC.GetTotalMemory(true);

// Ensure that the Array stays in memory and doesn't get optimized away
GC.KeepAlive(MyByteArray);

可以像这样获得流程广泛的东西

long Process_MemoryStart = 0;
Process MyProcess = System.Diagnostics.Process.GetCurrentProcess();
Process_MemoryStart = MyProcess.PrivateMemorySize64;

希望这会有所帮助;)

答案 2 :(得分:11)

ANTS memory profiler将告诉您确切地为每个对象/方法/等分配了多少。

答案 3 :(得分:10)

Here's a related post我们讨论了确定参考类型的大小。

答案 4 :(得分:7)

你也可以使用WinDbg和SOS或SOSEX(比如SOS带有更多命令和一些现有的改进)WinDbg扩展。用于分析特定内存地址对象的命令是!objsize

要记住的一个非常重要的项目是!objsize只给出了类本身的大小,并且不一定包括类中包含的聚合对象的大小 - 我不知道它为什么不这样做它有时令人沮丧和误导。

我在Connect网站上创建了2个功能建议,要求将此功能包含在VisualStudio中。请投票选择您想要添加的项目!

https://connect.microsoft.com/VisualStudio/feedback/details/637373/add-feature-to-debugger-to-view-an-objects-memory-footprint-usage

https://connect.microsoft.com/VisualStudio/feedback/details/637376/add-feature-to-debugger-to-view-an-objects-rooted-references

修改 我正在添加以下内容以澄清Charles Bretana提供的答案中的一些信息:

  1. OP询问“对象”的大小而不是“类”。对象是类的实例。也许这就是你的意思?
  2. 为对象分配的内存不包含JITted代码。 JIT代码存在于自己的“JIT代码堆”中。
  3. JIT只能逐个方法地编译代码 - 而不是在类级别。因此,如果一个方法永远不会被调用,那么它永远不会被JIT编译,因此永远不会在JIT代码堆上为它分配内存。
  4. 另外,CLR使用了大约8种不同的堆:

    1. Loader Heap:包含CLR结构和类型系统
    2. 高频堆:静态,MethodTables,FieldDescs,界面图
    3. 低频堆:EEClass,ClassLoader和查找表
    4. Stub Heap:CAS,COM包装器,P / Invoke
    5. 的存根
    6. 大对象堆:需要超过85k字节的内存分配
    7. GC堆:用户为应用分配了专用的堆内存
    8. JIT代码堆:由mscoreee(执行引擎)分配的内存和托管代码的JIT编译器
    9. 进程/基本堆:互操作/非托管分配,本机内存等
    10. HTH

答案 5 :(得分:6)

每个“类”都需要足够的内存来保存所有它的运行时调用的所有成员的jit编译代码(尽管如果你不调用方法很长一段时间,CLR就可以发布了如果你再次调用那个内存并重新启动它...加上足够的内存来保存类中声明的所有静态变量...但是这个内存每个类只分配一次,无论你有多少个类实例创造。

对于您创建的类的每个实例(并且没有收集垃圾),您可以通过将每个基于实例的声明变量的内存使用量相加来近似内存占用量...(字段)

引用变量(引用其他对象)需要4或8个字节(32/64位OS?) int16,Int32,Int64分别需要2,4或8个字节......

字符串变量为某些元数据元素占用额外的存储空间(加上地址指针的大小)

此外,对象中的每个引用变量也可以被视为“间接地”包括它指向的对象在堆上占用的内存,尽管您可能希望将该内存计为属于该对象而不是引用它的变量......

等。等

答案 6 :(得分:6)

要了解应用程序中内存分配的一般意义,请在WinDbg中使用以下sos命令

!dumpheap -stat

请注意,!dumpheap仅为您提供对象类型本身的字节,并且不包含它可能引用的任何其他对象类型的字节。

如果要查看特定对象类型的总保留字节数(对象引用的所有对象的所有字节数),请使用内存分析器,如点跟踪 - http://www.jetbrains.com/profiler/

答案 7 :(得分:5)

如果可以 - 序列化它!

Dim myObjectSize As Long

Dim ms As New IO.MemoryStream
Dim bf As New Runtime.Serialization.Formatters.Binary.BinaryFormatter()
bf.Serialize(ms, myObject)
myObjectSize = ms.Position

答案 8 :(得分:1)

有一个学术问题 运行时对象的大小是多少? 这很有意思,但它只能由一个分析器正确回答附加到正在运行的进程。我最近花了很长时间看这个,并确定没有足够准确和快速的通用方法,你可能希望在生产系统中使用它。像数组类型的数组这样的简单案例有简单的答案,但除此之外,最好的答案是 不要费心去尝试。你为什么想知道这个?是否有其他可用于同一目的的信息?

在我的情况下,我最终想要回答这个问题,因为我有各种有用的数据,但可以放弃以释放RAM以获得更多关键服务。这里的海报男孩是 Undo Stack 缓存

最后我得出结论,管理撤销堆栈和缓存大小的正确方法是查询可用内存量(这是一个64位进程,因此可以安全地假设它全部可用)然后如果存在足够大的RAM缓冲区,则需要添加更多项目,并且如果RAM不足,则需要删除项目。