我的应用程序非常耗费内存。它在一些大型数组中保存了大量数据。
我最近注意到偶尔的OutOfMemoryException。这些OutOfMemoryExceptions在我的应用程序(ASP.Net)耗尽800mb可用之前就已经发生了。 我已将问题跟踪到调整数组大小的代码区域。该数组包含一个大小为74字节的结构。 (我知道你不应该创建大于16字节的struct),但是这个应用程序是来自Vb6应用程序的端口)。我已经尝试将结构更改为类,这似乎已经解决了问题。
我认为更改为类解决问题的原因与以下事实有关:当使用结构并调整数组大小时,需要保留足够大以存储新数组的内存段(例如(currentArraySize + increaseBySize)* 74)无法找到。这导致OutOfMemoryException。
对于类不是这种情况,因为数组的每个元素只需要8个字节来存储指向新对象的指针。
我的想法是否正确?
答案 0 :(得分:3)
关于如何存储数组的假设是正确的。从struct更改为class会给每个实例增加一些开销,你将失去局部性的优势,因为所有数据都必须通过引用收集,但正如你所观察到的那样,它现在可以解决你的内存问题。
答案 1 :(得分:2)
当您调整数组大小时,它将创建一个新数据来保存新数据,然后复制数据,并且您将同时在内存中拥有相同数据的两个副本。正如你所料。
使用结构时,数组将占用struct size * number of elements
。使用类时,它只包含指针。
同样的情况也适用于List随着时间的推移而增加的大小,因此使用预期的项目数来初始化它是明智的,以避免调整大小和复制。
在32位系统上,你会发现大约800mb左右,你知道的。您可以尝试的一种解决方案是将您的结构放在磁盘上并在需要时读取它们。由于它们是固定大小,因此您可以轻松跳到文件的正确位置。
我在Codeplex上有一个用于处理大量数据的项目。它有一种可以进行自动增长的数组,如果你遇到问题再次将它们全部留在内存中,这可能有助于你的方案。
答案 2 :(得分:2)
您遇到的问题可能是由于大对象堆碎片而不是正常的内存不足导致所有内存都用完了。
请参阅http://msdn.microsoft.com/en-us/magazine/cc534993.aspx
解决方案可能就像通过大的固定增量而不是较小的随机增量来增长数组一样简单,这样当数组被释放时,LOH内存块可以重新用于新的大数组。
这也可以解释struct->类问题,因为struct可能存储在数组本身中,而类将是小对象堆上的一个小对象。
答案 3 :(得分:0)
.NET Framework 4.5.1能够在垃圾回收期间显式压缩大对象堆(LOH)。
GCSettings.LargeObjectHeapCompactionMode = GCLargeObjectHeapCompactionMode.CompactOnce;
GC.Collect();
中查看更多信息