2012-04-12 64 views
4

我正在努力解决一些内存使用问题。总体而言,我的应用程序会收集一些数据值,并使用C1 WPF图表和数据网格将它们可视化,最终将所有内容都放入PDF报告中。.NET进程内存使用率= 5x CLR堆内存?

使用YourKit分析我的进程我面临的情况是,CLR堆大小是〜120MB(这一切都很好),而进程内存大小是〜580MB。这几乎是我实际CLR堆大小的内存消耗的5倍。我的CLR峰值大小为220MB,而710MB的进程内存分配。

我很清楚,我的对象堆,堆栈等需要一些开销。在Java JVM中,我习惯的典型因素约为1.5倍。

如何解释这种过多的内存开销?这个过程是否仅仅分配了免费的备用堆空间?如果是的话,这是否解释了710MB与220MB?

回答

11

这里有一些附加说明。虽然我并不确定你的意思是“CLR堆大小”。 那里的CLR使用约8个不同的堆 - 这样的记忆,你在堆大小与VM大小占差的一些看到:

  1. 装载机堆:包含CLR结构和类型系统
  2. 高频堆:静,MethodTables,FieldDescs,接口映射
  3. 低频堆:EEClass,类加载器和查找表
  4. 存根堆:存根CAS,COM包装,P/Invoke的
  5. 大对象他用户分配的堆存储器专用于该应用
  6. JIT代码堆:存储器由mscoreee(执行引擎)分配和JIT编译器托管代码
  7. 处理AP:需要多于85K字节
  8. GC堆的存储器分配/基堆:互操作/非托管分配,本地存储器等可引起过度的存储器使用

另外两个项是存储器片段化(多发生在LOH或大对象堆)或高数量的线程。

存储器碎片的原因很多,排除这种情况的最好方法是使用WinDbg来分析GC堆上每个段的段大小。

就大量的线程而言,您为应用程序使用的每个线程分配了1MB的堆栈空间。该内存位于进程/基本堆中。因此,如果您有100个线程,则会有额外的100MB内存使用量。

HTH

+0

非常感谢您的宝贵和广泛的笔记特别是。有关.NET内存分配的解剖和潜在问题。就我而言,它终于证明是通过GDI +使用大块存储器的C1图形组件。作为一名Java专家,我完全不解这个.NET内存分析器工具。最后,我们必须通过限制那些C1图形组件的使用来解决这个问题。 – 2012-08-23 08:53:38

+0

很高兴帮助。我必须用WinDbg调试许多内存转储,这已经教会了我很多。在使用第三方组件时,我会密切关注两件事:首先,确保它们正在处理中,然后密切关注您的应用程序正在使用的Handles数量。这可以通过使用TaskManager(确保Handles col可见)或SysInternals ProcessExplorer轻松完成。通常,您将使用'using()'语句来确保组件及时处理。不过,我不熟悉WPF,所以这可能已经被框架所照顾。 – 2012-08-23 14:53:49

+0

Ben,你是怎么知道GDI +在消耗内存的? – RollRoll 2013-08-08 18:09:19

2

如果托管堆的总大小明显小于应用程序使用的专用字节,则可能是您分配了非托管内存并且(可能)未正确处置它。实现IDisposable的图形对象,流和其他对象在超出范围之前需要调用它们的方法,或者在using(){}语句中放置该方法,以便清理所有非托管资源。使用像ANTS Memory Profiler这样的工具可以告诉你如何分配你的内存以及实现IDisposable的对象。

+0

谢谢丹!这正是我错过的指针。也许ANTS可能对此无济于事(我已经在使用YourKit),因为它无法跟踪非托管内存泄漏。目前我正在尝试使用DebugDiag 1.2解决我的问题 – 2012-04-24 15:59:37

+0

我不熟悉DebugDiag,但Smartbear的AQTime允许您分析托管代码和非托管代码。它不像ANTS那么容易使用,但有更多的信息可用。请参阅http://smartbear.com/products/qa-tools/application-performance-profiling – 2012-04-24 16:28:56