强制数组的垃圾收集,C#

Joh*_*Doe 17 c# arrays xna garbage-collection out-of-memory

我有一个问题,其中一对三维数组分配了大量的内存,程序有时需要用更大/更小的替换它们并抛出OutOfMemoryException.

示例:有5个分配的96MB阵列(200x200x200,每个条目中有12个字节的数据),程序需要用210x210x210(111MB)替换它们.它以类似于此的方式执行:

array1 = new Vector3[210,210,210];
Run Code Online (Sandbox Code Playgroud)

其中array1-array5与先前使用的字段相同.这应该将旧数组设置为垃圾收集的候选者,但是看起来GC不能足够快地执行并且在分配新数组之前分配旧数组 - 这会导致OOM - 而如果它们在新分配之前释放,则空间应该是足够.

我正在寻找的是一种做这样的事情的方法:

GC.Collect(array1) // this would set the reference to null and free the memory
array1 = new Vector3[210,210,210];
Run Code Online (Sandbox Code Playgroud)

我不确定完整的垃圾收集是否是一个好主意,因为该代码可能(在某些情况下)需要经常执行.

有没有正确的方法呢?

Cha*_* Im 15

这不是原始问题"如何强制GC"的确切答案,但我认为它将帮助您重新检查您的问题.

看到你的评论后,

  • 放GC.Collect(); 确实似乎有所帮助,但仍然没有完全解决问题 - 由于某种原因,当分配大约1.3GB时程序仍然崩溃(我正在使用System.GC.GetTotalMemory(false);来查找分配的实际金额).

我怀疑你可能有内存碎片.如果对象很大(如果我没记错的话,在.net 2.0 CLR下85000字节,我不知道它是否已被更改),该对象将被分配在一个特殊的堆,大对象堆(LOH)中.GC确实回收了LOH中无法访问的对象所使用的内存,但是,由于性能的原因,在LOH 中不执行压缩,因为它对其他堆(gen0,gen1和gen2)执行压缩.

如果你经常分配和释放大对象,它会使LOH碎片化,即使你有更多的可用内存而不是你需要的内存,你可能不再有连续的内存空间,因此,会得到OutOfMemory异常.

我现在可以想到两个解决方法.

  1. 转移到64位机器/操作系统并利用它:)(最简单,但可能最难,取决于您的资源限制)
  2. 如果你不能做#1,那么首先尝试分配一大块内存并使用它们(它可能需要编写一些辅助类来操作一个较小的数组,实际上它位于一个更大的数组中)以避免碎片.这可能有点帮助,但它可能无法完全解决问题,您可能不得不处理复杂性.

  • 或者切换到使用锯齿状数组 - Vector3 [210] [210] [210],它会分配分配而不是使用一个很大的内存块 (2认同)

Pop*_*lin 9

好像你遇到了LOH(大对象堆)碎片问题.

大对象堆

CLR内部大对象堆未被覆盖

您可以使用SOS检查是否存在loh碎片问题

查看此问题以获取如何使用SOS检查loh的示例.


Mit*_*eat 7

强制垃圾收集并不总是一个好主意(在某些情况下它实际上可以促进对象的生命周期).如果必须,你会使用:

array1 = null;
GC.Collect();
array1 = new Vector3[210,210,210];
Run Code Online (Sandbox Code Playgroud)

  • 如果运行时找不到足够的内存用于分配,它将触发一个集合,因此不需要显式调用GC.Collect. (5认同)
  • 毕竟John Doe确实要求*强制*垃圾收集. (3认同)
  • 不,你根本不应该打电话给GC.Collect.最好的解决方案是在分配新数组之前删除引用,让垃圾收集器在没有干扰的情况下完成工作. (2认同)
  • 放GC.Collect(); 确实似乎有所帮助,但仍然没有完全解决问题 - 由于某种原因,当分配大约1.3GB时程序仍然崩溃(我正在使用System.GC.GetTotalMemory(false);来查找分配的实际金额).只是取消引用没有任何帮助. (2认同)