编辑:我将其重新表述为问题并将答案移至答案部分...
在一个相对复杂的多线程 .NET
应用程序中,我遇到了 OutOfMemoryException
,即使在我认为没有理由的情况下也是如此。
情况:
- 应用程序是 32 位的。
- 该应用程序创建了许多(数千个)被认为很小(小于大约 85kB)的短期对象。
- 此外,它还会创建一些(数百个)被认为是大型(大于约 85kb)的短期对象。这意味着这些对象是在 LOH(大对象堆)中分配的。
- 这些对象的两个类都定义了终结器 (
~MyFinalizer(){...}
)。
症状:
OutOfMemoryException
- 通过内存分析器查看应用程序,有数千个小对象符合收集条件,但未被收集,因此阻塞了大量内存。
问题:
- 为什么应用会耗尽整个堆?
- 为什么内存中仍然存在大量“死”对象?
最佳答案
经过深入调查,我找到了原因。由于花费了一些时间,我想让其他遇到同样问题的人也能轻松一些。
原因:
- 应用只有大约 2GB 的虚拟地址空间。
- LOH 在设计上并未压缩,因此可能会很快碎片化,但对于上述大对象的数量,这应该不是任何问题。
- 由于垃圾收集器的设计,如果有定义终结器的对象(即使是空的),它会被视为 Gen2 对象并放入 GC 的终结队列中。这意味着,在完成之前(调用
MyFinalizer
)它只会阻塞内存。在上述应用的情况下,运行终结器的 GC 线程没有机会尽快完成其工作,因此堆已耗尽。
解决方案:
不要对此类“动态”对象(高容量、短生命周期)使用终结器,以其他方式解决终结代码...
非常有用的资源:
关于c# - 托管堆 OutOfMemory,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/25033335/