2011-02-04 111 views
3

我想追蹤我的.NET應用程序中的內存泄漏。 Windows任務管理器報告內存使用率保持不變,而Process Explorer報告內存使用率在上升。任務管理器不同意Process Explorer?

在任務管理器中,我正在查看唯一的存儲器列「Memory(Private working set)」。在進程資源管理器中,我正在查看「專用字節」列,因爲它在提升,而「工作集」下的值不是。

現在,當然,Process Explorer是正確的,因爲經過幾次分配,我的應用程序崩潰了內存不足異常。問題是,爲什麼任務管理器誤報應用程序的內存使用量?不僅如此,還會誤報全局系統空閒內存(「性能」選項卡中的圖形保持不變)。

我的代碼不應該被需要,但這裏是爲了完整性。它顯示一個空的窗口,包含一個大數組。當按下任意鍵時,窗口關閉,並打開一個新窗口,保存一個新陣列。舊窗口已泄漏,可能是由於qt4dotnet GUI庫中的一個錯誤。

using System; 
using com.trolltech.qt.gui; 

namespace LeakTest 
{ 
    class Test : QWidget 
    { 
     public byte[] Data = new byte[1000 * 1000 * 100]; 

     public Test() 
     { 
      show(); 
      GC.Collect(); // so measurements are more accurate 
     } 

     protected override void keyPressEvent(QKeyEvent arg__1) 
     { 
      disposeLater(); 
      new Test(); 
     } 

     [STAThread] 
     static void Main(string[] args) 
     { 
      QApplication.initialize(args); 

      new Test(); 

      QApplication.exec(); 
     } 
    } 
} 

操作系統:Windows 7

有趣,注意:當我提出 「數據」 尺寸[1000 * 1000 * 100][1]的二維交錯數組,任務管理器確實報告提高內存的使用情況。

+1

我會強烈反對使用任務管理器/進程資源管理器來查找.NET內存泄漏。通常情況下,我使用[ANTS Memory Profiler](http://www.red-gate.com/products/dotnet-development/ants-memory-profiler/),甚至使用這種專用工具,也很難找到泄漏。如果我剛剛使用了任務管理器,我就沒有機會在過去找到我的泄漏。 – 2011-02-04 20:27:06

+1

從未使用過的頁面不需要任何支持,因爲它們只能在第一次訪問時被刪除。所以他們算作專用字節,但不需要任何RAM,不屬於工作集。 – CodesInChaos 2011-02-04 20:29:31

回答

6

它們是兩種完全不同的記憶手段。工作集是程序使用的RAM數量。這是一個不斷變化的數字,並受到其他進程需要多少RAM的影響。您不能用完RAM,Windows通過將映射頁面交換到頁面文件來使RAM可用。

私有字節是虛擬的數量您的程序使用的內存不與任何其他進程共享。在32位計算機上,可以使用2千兆字節的虛擬內存。它需要在代碼和數據之間共享。當可尋址數量的虛擬內存中沒有足夠的空間來滿足請求的分配時,您會得到OOM。是的,這是更準確的數字。

一次請求100兆字節是有風險的。虛擬內存空間可能會變得碎片化,過了一段時間後,仍然會有大量的免費虛擬內存,但不會有足夠大的空洞來容納100兆字節。鋸齒陣列解決了這個問題,因爲它是一個數組數組,所需的塊更小,因此可以很容易地適應任何留下的孔。

64位操作系統完全解決了這個問題。您的程序有許多可用的地址空間,實際上僅受分頁文件的最大大小的限制。你根本無法用完大洞。

1

如果您想追蹤內存泄漏,並且您無法通過閱讀代碼來找到它,那麼您可能需要一個專爲此作業設計的真實工具。

無論是任務管理器還是Process Explorer都不是用於調試內存泄漏的適當工具 - 您希望能夠告訴您在哪裏分配未返回的內存。