2014-09-05 137 views
6

我想追查一個更大的C#程序中產生多個線程的內存泄漏。在這個過程中,我創建了一個我用來測試一些基本事物的小程序,並且發現了一些我實際上不理解的行爲。線程內存泄漏

class Program 
{ 
    static void test() 
    { 
    } 

    static void Main(string[] args) 
    { 
     while (true) 
     {    
      Thread test_thread = new Thread(() => test()); 
      test_thread.Start(); 
      Thread.Sleep(20); 
     } 
    } 
} 

運行這個程序,我發現程序的內存使用量穩步增加而不停止。在短短几分鐘內,內存使用量超過了100MB,並持續攀升。如果我註釋掉test_thread.Start()這一行,程序使用的內存最大值大約爲幾兆字節,並保持穩定。我也嘗試使用GC.Collect()在while循環結束時強制垃圾收集,但它似乎沒有做任何事情。

我認爲一旦函數完成執行後允許GC拖動它,線程就會被解除引用,但這似乎並沒有發生。我不應該在這裏更深入地理解某些東西,我希望能夠幫助我們解決這個問題。提前致謝!

回答

9

這是設計,你的測試程序應該表現出失控的內存使用。您可以從Taskmgr.exe中查看潛在的原因。使用視圖+選擇列並勾選「處理」。觀察您的流程手柄數量如何穩步增加。內存使用量隨之增加,反映了句柄對象使用的非託管內存。

設計選擇非常有勇氣,CLR每個線程使用5個操作系統對象。管道,用於同步。這些對象本身是一次性的,設計選擇是而不是使Thread類實現IDisposable。這對於.NET程序員來說是相當困難的,很難在正確的時間進行Dispose()調用。在任務類設計中沒有展示的勇氣,造成了大量的手動和general advice not to bother

這是不是通常是一個設計良好的.NET程序中的問題。 GC運行的頻率足以清理這些操作系統對象。線程對象正在謹慎地創建,使用ThreadPool作爲測試程序使用的非常短的運行線程。

它可以,我們無法看到您的真實程序。謹防從這樣的綜合測試中得出太多結論。您可以使用Perfmon.exe查看GC統計信息,爲您提供一個足夠頻繁運行的想法。一個體面的.NET內存分析器是選擇的武器。 GC.Collect()是備用武器。例如:

static void Main(string[] args) { 
    int cnt = 0; 
    while (true) { 
     Thread test_thread = new Thread(() => test()); 
     test_thread.Start(); 
     if (++cnt % 256 == 0) GC.Collect(); 
     Thread.Sleep(20); 
    } 
} 

而且你會看到它現在反彈,從未遠遠高於4 MB。