我目前的项目包括植被模拟,能够渲染大量实例树模型,随着时间的推移逐渐增长和重现。
我目前在这行代码中获得了一致的OutOfMemory异常
if (treeInstances.Length <= currentIndex)
Array.Resize(ref treeInstances, currentIndex + 500);
当模拟超出treeInstances
数组的通常范围时,此代码运行,并使其分配一个新的数组,并为树提供额外的500个插槽。
鉴于我可以看到数组失败时的大小(通常介于3000到5000个实例之间)和TreeInstance
结构的大小(20个浮点数),我确信我的问题不在于数组的原始大小。即使考虑到它必须在resize / 8进程期间暂时加倍(因为Array.Resize()
分配一个新数组),假设我的数学运算正确,它仍然不到半个MB。
更多详情:
TreeInstance
是一个简单的结构,具有每棵树的变换矩阵和颜色。 treeInstances
是一个TreeInstance[]
数组。它仅在此处直接使用,在上面的代码行中。 treeInstances
还有一个属性TreeInstances
,可通过get;set;
TreeInstances
用于设置每棵树生长时的变换矩阵和颜色,并作为Draw
例程的一部分提供给Instancing方法。 TreeInstances
执行各种功能而不修改其内容(包括在DynamicVertexBuffer.SetData
操作中将其用作源)。答案 0 :(得分:1)
C#旨在处理小内存分配比大内存分配好得多。当您执行Array.Resize时,您正在强制分配新的内存块,复制的数据然后旧块无效。这是一种非常有效的分段堆算法: - )
如果你知道你的数组在开始时需要多大,那就让你的数组大小。如果你不这样做,我建议你使用List或类似的类。该课程按每个项目分配。
我站起来纠正,谢谢你让我保持诚实。我太习惯于处理类而不是结构。我应该更清醒。
如果将TreeInstance更改为类,则List将成为地址数组,而TreeInstance可以/将以较小的块分配。新建所有TreeInstance都需要进行一些代码更改。
答案 1 :(得分:0)
看起来我找到了我的问题的答案,跟随Dweeberly对我的Array.Resize()
系统的描述是“一个非常有效的分解堆的算法”。这是我的一个概念化问题:我不明白Out of Memory Exceptions可能是由于没有足够的连续内存引起的,而是假设我因为Garbage Collection没有捕获数组而达到某种限制。/ p>
Eric Lippert撰写的这篇博文让我直截了当:
对于任何处理Out of Memory Exceptions的人来说,或者作为游戏编程中任何人的一般知识都值得一读。
简短的回答是这样的:在为32位Windows编译的程序中,重复分配然后删除大对象,就像我通过Array.Resize()
所做的那样,可以将地址空间分割成空白区域的“块”与您指定的对象一样大。随后,尝试分配大于任何这些空闲块的对象将引发Out Of Memory异常,即使您的累积内存也要大得多。
如上所述,适当的响应只是为了避免重复调整数组大小:我只需要理解为什么。在我的例子中,这意味着重写Instanced Model方法只绘制一个更大的数组的子集,而不是整个数组。之后,这是一种分配比初始化期间所需的更大阵列的简单方法。