2011-12-19 171 views
51

今天我的應用程序拋出了OutOfMemoryException。對我來說,這總是幾乎不可能,因爲我擁有4GB RAM和大量虛擬內存。當我嘗試將現有集合添加到新列表時發生錯誤。C#:內存不足異常

List<Vehicle> vList = new List<Vehicle>(selectedVehicles); 

據我瞭解,這裏沒有太多的內存分配在這裏,因爲我的新列表應該包含的車輛已經存在於內存中。我不得不承認Vehicle是一個非常複雜的課程,我試圖一次將約50,000個項目添加到新列表中。但是由於應用程序中的所有Vehicle都來自僅200MB大小的數據庫:我不知道此時可能會導致OutOfMemoryException

+7

什麼是'selectedVehicles'的值(和類型)? – harold 2011-12-19 16:01:15

+1

當拋出'OutOfMemoryException'時,你是否使用調試器附加到進程,並查看可能出現的問題?對象有多大?對於對象大小,.NET Framework的硬限制爲2 GB,減去框架本身消耗的開銷。 – 2011-12-19 16:05:00

+1

車輛可能是一個結構而不是一個類? – 2011-12-19 16:05:58

回答

57

兩點:

  1. 如果您運行的是32位的Windows,你不會有所有的4GB訪問,只有2GB。
  2. 不要忘記List的底層實現是一個數組。如果你的內存很碎,可能沒有足夠的連續空間來分配List,儘管總共有很多可用內存。
+21

在64位Windows中只有2 GB可用。這是.NET Framework的一個限制,而不僅僅是32位地址空間。 – 2011-12-19 16:18:12

+0

+1對於第2點。他可以嘗試編寫一個分段列表。 – 2011-12-19 16:19:20

+22

@CodyGray這將是每個對象(數組)2GB,而不是總共2GB。 – 2011-12-19 16:21:09

10

存儲在數據庫中的數據與應用程序中的存儲器相比是非常不同的。

沒有一個辦法讓你的對象的確切大小,但你可以這樣做:對象一定量已經加載完畢後

GC.GetTotalMemory() 

,看看你的內存是多少改變,因爲你加載列表。

如果是導致過多內存使用情況的列表,那麼我們可以考慮將其最小化的方法。例如,爲什麼您希望首先將50,000個對象一次加載到內存中?根據你的需求調用數據庫不是最好的嗎?

如果你看看這裏:http://www.dotnetperls.com/array-memory你也會看到.NET中的對象比他們的實際數據更大。通用列表甚至比數組更多的是內存。如果你的對象中有一個通用列表,那麼它將會增長得更快。

7

OutOfMemoryException異常(在32位機)就是經常約碎片作爲存儲實際的硬限制 - 你會發現很多關於這一點,但這裏是我的第一個谷歌打簡要討論這個問題:http://blogs.msdn.com/b/joshwil/archive/2005/08/10/450202.aspx。 (@Anthony Pegram在他上面的評論中提到了同樣的問題)。

這就是說,有可能想到上面代碼中另外一個可能性:由於您使用的「IEnumerable的」構造到列表中,你可能給對象的任何提示,以規模您傳遞給List構造函數的集合。如果傳遞的對象不是集合(不實現接口),那麼List實現將需要增長几次(或多次),每次都會留下一個太小需要垃圾收集的數組。垃圾收集器可能不會很快到達這些被丟棄的數組,並且會出錯。

最簡單的解決方法是使用List(int capacity)構造函數來告訴框架需要分配的數組大小(即使您正在估計並猜測「50000」),然後使用AddRange(IEnumerable collection)方法實際上填充你的列表。

所以,最簡單的「修復」如果我是對的:更換

List<Vehicle> vList = new List<Vehicle>(selectedVehicles); 

List<Vehicle> vList = new List<Vehicle>(50000); 
vList.AddRange(selectedVehicles); 

所有的其他意見和答案仍然適用於整體設計決策方面 - 但這可能是一個快速修復。

注意(@Alex在下面評論),如果selectedVehicles不是ICollection,這只是一個問題。

+3

如果selecyedVehicles是一個集合,構造函數將分配正確的數組大小。無需經過AddRange。 – Alex 2011-12-19 16:36:10

3

您不應該嘗試一次帶入所有列表,數據庫中元素的大小與內存中元素的大小不同。 如果你想處理你應該爲每個循環使用的元素,並利用實體框架延遲加載,所以你不要一次把所有的元素放入內存中。 如果你想顯示列表使用分頁(.Skip()和。取())

58

.Net4.5沒有一個對象的2GB的限制了。 此行添加到的App.config

<runtime> 
    <gcAllowVeryLargeObjects enabled="true" />  
</runtime> 

,這將是可能沒有得到OutOfMemoryException異常

創建非常大的對象請注意,它會在x64 OS唯一的工作!

+0

做得很好。這對我有用,注意必須將Build目標更改爲x64。 – 2015-10-19 18:42:42

+0

也適用於ASP.NET 4.5?使用本地報告,*我的應用程序v1(asp.net 3.5 - clr 2.0 - 經典)*工程***確定***,但我的應用程序v2(asp.net 4.5,clr 4.0,經典)生成*** OutOfMemoryException錯誤***,在同一個IIS服務器_ – Kiquenet 2015-10-30 12:48:10

67

3歲的話題,但我發現了另一個工作解決方案。 如果你確定你有足夠的可用內存,運行64位操作系統,並仍然得到例外,一定要在你的項目屬性來設置這個選項 enter image description here

+1

沒有圖像存在 – TheGameiswar 2017-01-10 18:19:12

4

我的開發團隊解決了這一情況:

我們增加將以下Post-Build腳本放入.exe項目並再次編譯,將目標設置爲x86並增加1.5 gb,同時還使用3.2 gb的x64 Platform目標增加內存。我們的應用程序是32位。

相關網址:

腳本:

if exist "$(DevEnvDir)..\tools\vsvars32.bat" (
    call "$(DevEnvDir)..\tools\vsvars32.bat" 
    editbin /largeaddressaware "$(TargetPath)" 
)