托管堆OutOfMemory

时间:2014-07-30 09:33:35

标签: c# .net garbage-collection out-of-memory

编辑:我将其重新表述为一个问题并将答案移到答案部分......

在一个相对复杂的多线程.NET应用程序中,我经历了OutOfMemoryException,即使在我认为没有理由的情况下也是如此。

情况:

  • 申请是32位。
  • 该应用程序会创建大量(数千个)短暂的物体,这些物体被认为很小(小于约85kB)。
  • 另外它会创建一些(数百个)短寿命对象,这些对象被认为是大的(大于约85kb)。这意味着这些对象在LOH(大对象堆)中分配。
  • 这些对象的两个类都定义了终结器(~MyFinalizer(){...})。

症状:

  • OutOfMemoryException
  • 通过内存分析器查看应用程序,有成千上万的小对象有资格收集,但没有收集,因此会阻止大量内存。

问题:

  • 为什么应用耗尽整个堆?
  • 为什么有很多"死了"对象仍然存在于内存中?

2 个答案:

答案 0 :(得分:2)

经过深入调查后,我找到了原因。由于花了一些时间,我想让遇到同样问题的其他人轻松一点。

原因:

  • App只有大约2GB的虚拟地址空间。
  • LOH在设计上并没有被压缩,因此可能很快就会碎片化,但对于上面提到的大型物体数量,它不应该是任何问题。
  • 由于垃圾收集器的设计,如果是定义终结器的对象(即使只是空),它将被视为Gen2对象并被放入GC的终结队列中。这意味着,在最终确定之前(MyFinalizer被调用)它只会阻塞内存。在提到的应用程序的情况下,运行终结器的GC线程没有机会按需要尽快完成工作,因此堆耗尽。

解决方案:

不要将终结器用于这样的"动态"对象(高容量,短寿命),以其他方式解决完成代码......

非常有用的来源:

答案 1 :(得分:0)

尝试使用分析器,例如:

  • ANTS Memory Profiler
  • ANTS Performance Profiler
  • Jetbrains Performance Profiler

对于LOH强制使用GC:

            GC.Collect();
            GC.WaitForPendingFinalizers();