2009-08-26 21 views
4

我在解決.NET 2.0 Windows Service應用程序中的OutOfMemory異常問題。爲了更好地理解這個問題,我開始編寫一個簡單的.NET WinForm測試應用程序,該應用程序通過構建ArrayList來生成OOM異常,直到引發OOM異常爲止。捕獲並記錄異常,我可以單擊表單按鈕再次運行OOME。我發現奇怪的是第四次運行,在下一個OOME大約一半之前消耗的內存量。下面列出的結果每次運行時都是一致的。目測任務管理器也確認了這種行爲。不幸的是,當試圖獲得更好的統計數據時,Perfmon凍結了。有人可以解釋爲什麼內存限制在3次運行後降低了嗎?我對GC的理解很淺薄。您還可以看到我在運行幾次後運行了一個GC.Collect(),但它沒有幫助降低限制。瞭解.NET GC和OutOfMemory異常

更新:我還發現使用常量字符串與每個數組列表項目的新對象有很大的區別。代碼很簡單:

const string TEST_TEXT = "xxxxxxxxxx"; 
ArrayList list = new ArrayList(); 
while (true) 
{ 
    list.Add(TEST_TEXT); 
} 

開始循環:內存10350592

  • OOM拋出異常
  • 數組大小:134217728

結束循環:內存

開始循環:存儲器550731776

  • OOM拋出異常
  • 數組大小:134217728

END LOOP:存儲器551682048

開始循環:存儲器551813120

  • OOM例外引發
  • 數組大小:134217728

END LOOP:存儲器551772160

開始循環:存儲器551903232

  • OOM拋出異常
  • 數組大小:67108864

結束循環:內存282,869,760

開始循環:存儲器283004928

  • OOM拋出異常
  • 數組大小:67108864

END LOOP:存儲器282910720

GC。收集手動觸發

開始循環:內存

  • OOM拋出異常
  • 數組大小:67,108,864

結束循環:內存

+0

那麼你的測試程序做什麼呢?它如何「建立一個數組」? – jalf 2009-08-26 18:39:57

+0

請發佈您的代碼。 – 2009-08-26 18:41:38

+0

查看上面的代碼示例。 – 2009-08-27 13:55:44

回答

8

這裏有幾個這些點合在一起有希望給予y OU足夠的信息來回答你的問題:

  • 儘管它的名字,OutOfMemory exceptions are just as likely to mean you are out of Address Space as physical RAM.
  • GC.Collect的不收集所有優秀的RAM。在.net中的垃圾收集是非確定性,意思是有沒有辦法運行清理所有您的RAM。
  • .NET中的垃圾收集器是,當對象生存收集它向上移動到較高的生成,使得它甚至不太可能被收集的意思。
  • 通過你的內存溢出的異常被拋出的時候,你的陣列有可能已經生存了幾集的嘗試或者甚至被移到LargeObjectHeap。
  • 陣列大小是固定的。要將新元素添加到數組中,您必須完全重新分配數組。 (使用像列表這樣的結構可以獲得更好的測試結果)。
3

由於您正在構建數組,因此我假設您正在爲每次運行構建一個大數組。如果是這種情況,它將被存儲在大對象堆中(因爲它將大於85000字節)。 LOH並非像世代堆一樣壓縮,所以您看到的大小下降可能是由於堆碎片造成的。

+0

對不起 - 我實際上使用ArrayList。見上面的代碼。 – 2009-08-27 13:58:54

+0

現在幾乎沒有理由使用ArrayList,但在這種情況下它並沒有真正的區別,castro ArrayList也在內部使用數組。 – 2009-08-27 15:30:17