2013-10-25 48 views
3

我目前的項目包括一個植被模擬,能夠渲染大量隨時間增長和再現的實例樹模型。如何在Array.Resize期間防止OutOfMemory異常?

我目前得到的這行代碼

if (treeInstances.Length <= currentIndex) 
    Array.Resize(ref treeInstances, currentIndex + 500); 

當仿真超過treeInstances陣列通常的界限此代碼運行,並導致它分配一個新的數組附加一致OutOfMemory異常樹木500個插槽。

鑑於我可以看到它失敗時的數組大小(通常在3000到5000個實例之間)和TreeInstance struct(20浮點數)的大小,我確定我的問題不在於原始大小的陣列。即使考慮到在resize/8過程中(因爲Array.Resize()分配了一個新數組),在假設我的數學正確的情況下它仍然不到半個MB,它必須暫時加倍。

因此,我假設一定有一些我錯過了。垃圾收集器可能不會刪除舊數組嗎?

更多細節:

  • TreeInstance是一個簡單的結構,每個樹的變換矩陣和顏色。
  • treeInstancesTreeInstance[]陣列。它僅在這裏直接使用,在上面的代碼行中。
  • treeInstances還具有屬性,TreeInstances,其經由get;set;
  • TreeInstances訪問它用於設置,因爲它生長的變換矩陣,並且每個樹的顏色,和被饋送到實例化方法作爲Draw例程的一部分。
  • 我不太熟悉的Instancing方法,但使用TreeInstances執行各種功能而不修改它的內容(包括將它用作DynamicVertexBuffer.SetData操作中的源代碼)。
+1

你爲什麼要分配自己的數組?你有沒有考慮使用名單?根據所涉及的數組大小,+500分配可能不是增長數組的最有效方式。他們可能會在大對象堆上留下漏洞。如果可能,我的建議是使用列表。如果不使用內存分析器並查看內存佔用情況。 – hawk

+1

考慮到你的結構中有20個浮點數,並且在數組中有3000-5000個元素,你肯定會在大對象堆中結束。一種策略是預先分配足夠大的陣列。 – hawk

+0

我正在使用我自己的數組,因爲實例化繪製方法將數組作爲參數,並且它似乎是直接分配數組的更好方法,而不是每秒60次調用列表 .ToArray()。不過,我現在還不能確定。 – Quasar

回答

0

看起來像我找到了我的問題的答案,跟隨Dweeberly的描述我的Array.Resize()系統是「一個非常有效的算法來分割你的堆」。這是我的一個概念化問題:我不明白Out Of Memory Exceptions可能是由於沒有足夠的連續內存而導致的,而是因爲Garbage Collection沒有捕獲數組而導致我遇到某種限制。

本博客文章由埃裏克利珀設置我直:

http://blogs.msdn.com/b/ericlippert/archive/2009/06/08/out-of-memory-does-not-refer-to-physical-memory.aspx

非常值得的人與內存不足異常,或作爲一般知識打交道的人在遊戲編程讀取。

簡短的回答是:在爲32位Windows編譯的程序中,通過Array.Resize()重複分配然後除去大對象,可以將您的地址空間分割成空白空間的「塊」您正在分配的對象。隨後,嘗試分配大於這些空閒塊的對象會引發內存不足異常,即使您的累積內存更大。

正如上面所建議的那樣,恰當的迴應就是避免反覆調整陣列大小:我只需要了解爲什麼。在我的情況下,這意味着重寫Instanced Model方法只繪製一個較大數組的子集,而不是整個數組。之後,這是一個簡單的方法來分配一個比我在初始化期間需要的更大的數組。

1

C#旨在處理比大型內存更好的小內存分配。當你做一個Array.Resize時,你迫使一個新的內存塊被分配,數據被複制,然後舊塊無效。這是一個非常有效的算法,用於分割你的堆:-)

如果你知道你的數組需要在開始時有多大,使你的數組​​大小。如果你不這麼做,我建議你使用List或類似的類。該班級按每個項目分配。

我糾正了,謝謝你讓我保持誠實。我太習慣於處理類而不是結構。我應該更清醒。

如果將TreeInstance更改爲一個類,則List變爲和地址數組,並且TreeInstance的可以/將以更小的塊分配。一些代碼更改將需要新增所有TreeInstance。

+0

錯誤; '列表'由單個數組支持。 – SLaks

+3

你知道'List '使用一個數組作爲它的底層存儲機制嗎?它也不會爲每個項目分配空間,它將分配一個新陣列,該陣列是當前底層陣列大小的兩倍,並在空間不足時將當前陣列複製到該陣列。 –