2012-04-12 83 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