簡體   English   中英

在仍有空閑VM空間的情況下拋出System.OutOfMemoryException

[英]System.OutOfMemoryException is thrown while still having free VM space

在詢問之前,我會做一個小小的免責聲明:是的,我知道虛擬內存,物理內存和工作集之間的區別。 以下所有數字均指虛擬內存。

情況如下:我們有一個32位C#應用程序,它導入x86 C ++庫(具有大量本機依賴性,因此目前無法遷移到x64)。 該應用程序通過非托管組件加載大型數據集,然后嘗試顯示它(報告)。

但是,當數據集特別大時,在向列表添加項目時會拋出OutOfMemory異常,如下面的代碼所示:

這里不足為奇。 然而,令人驚訝的是,該應用程序仍然擁有大約280MB的免費VM。

在調試純粹的非托管應用程序(C ++)時,情況從未如此 - 只有在沒有剩余空閑虛擬機的情況下,或者如果沒有足夠大小的空閑地址空間塊時,才能實現bad_alloc。

因此,問題 - 這可能是什么原因? 我理解如何解決這個問題 - 非托管組件確實會占用大量內存,並且會產生大量碎片 - 但是OutOfMemoryException出現這么早的原因是什么?

有問題的代碼如下所示:

List<Cell> r = new List<Cell>(cols);
for (int j = 0; j < cols; j++)
{
    r.Add(new CustomCell()); // The exception is thrown on this line
}

在異常時刻,列表(在一個出現時)有85個項目,它的容量是200-something(列數,如構造函數中所示)。 因此,異常最有可能發生在CustomCell分配中。 CustomCell對象有很多字段,但總共不到1KB。 280MB的可用內存位於64KB到14MB的塊中 - 因此應該有足夠的空間來分配它。

有大量高達14Mb的塊。 失敗的操作是創建總共小於1KB的對象

14 MB肯定接近危險區域。 GC分配VM的方式與對象大小無關。 GC堆是從稱為“段”的VM塊創建的。 程序啟動時段大小為2 MB,但是當程序使用大量內存時,GC會動態增加新段的分配。 顯然你使用了大量的內存。 您無法做任何事情來影響VM分配或避免VM地址空間碎片。

顯然,您太接近32位進程的VM限制。 您需要徹底修改代碼,以便您可以少花錢。 或者您需要在您的先決條件列表中放置64位操作系統。 這可以為32位進程提供4千兆字節的VM地址空間。 您將需要額外的構建步驟來利用它,如本答案中所述

編輯

在添加代碼之前編寫。 看起來你已經這樣做了:

List實例具有容量。 如果超出容量,則會調用不斷增長的算法,使列表的容量加倍。

 
 
 
  
  //decompiled from List<T> private void EnsureCapacity(int min) { if (this._items.Length >= min) return; int num = this._items.Length == 0 ? 4 : this._items.Length * 2; if ((uint) num > 2146435071U) num = 2146435071; if (num < min) num = min; this.Capacity = num; //causes a copying of src array to a new array }
 
  

這可能導致意外的內存分配。 如果您能夠預測列表的最終大小,請預先分配並避免加倍:

 
 
 
  
  var myList = new List<SomeType>(expectedCapacity)
 
  

當您有64位應用程序時,您還必須小心,如果要在數組中加載報表,則最大數組大小為2 GB。

更多信息: 關於大數組聲明的OutOfMemoryException

這也可能適合你: http ://social.msdn.microsoft.com/Forums/en-US/1a12abaa-50bd-4d28-b3c1-9de06a1488e9/how-to-create-an-extremely-large-arrayobject- 2-GB-而不-使用-鋸齒狀arrays-

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM