引用:
GC是自我调整的,根据应用程序的内存要求进行调整。在大多数情况下,通过编程方式调用GC会妨碍该调整。“帮助”GC通过调用GC.Collect很可能不会提高应用程序的性能。
我正在处理在某一时间点消耗大量内存的应用程序。当我完成代码中消耗该内存的操作时,我调用GC.Collect。如果我不这样做,我会得到内存不足异常。这种行为不一致,但大约30%的时间,我会遇到内存不足异常。添加了GC.Collect后,我从未遇到过此内存不足异常。即使这份最佳实践文件反对我的做法,我的行动也是合理的吗?GC是自我调整的,根据应用程序的内存要求进行调整。在大多数情况下,通过编程方式调用GC会妨碍该调整。“帮助”GC通过调用GC.Collect很可能不会提高应用程序的性能。
我正在处理在某一时间点消耗大量内存的应用程序。当我完成代码中消耗该内存的操作时,我调用GC.Collect。如果我不这样做,我会得到内存不足异常。这种行为不一致,但大约30%的时间,我会遇到内存不足异常。添加了GC.Collect后,我从未遇到过此内存不足异常。即使这份最佳实践文件反对我的做法,我的行动也是合理的吗?GC的运行机制中,内存中的对象是“分代”的,早期代被更频繁地垃圾回收,这有助于通过不一直回收长期存在的对象来提高性能。
因此,当您自己调用GC.Collect()
时会发生两件事情。第一,您会花费更多时间进行垃圾回收,因为正常的后台回收将继续进行,而您的手动GC.Collect()也要同时执行。第二,在某些情况下,您会将内存占用时间延长,因为您强制将某些东西放入高级别代中,而它们实际上不需要进入那里。换句话说,自己使用GC.Collect()几乎总是一个坏主意。
在一些情况下,垃圾回收器的性能并不一定好。其中之一是大对象堆,这是专门为大于某个大小(80,000字节,如果我没记错的话)的对象创建的特殊代。这一代很少回收,几乎从不压缩。这意味着随着时间的推移,您可以在内存中留下许多可观的空洞,但这些空间实际上没有被占用,是可以被其他进程使用的。但它仍然在您的进程中占用了地址空间,而默认情况下您的地址空间限制为2GB。
这是OutOfMemory异常的一个非常常见的来源,因为您并没有实际使用那么多内存,但是您所有的地址空间都被大对象堆的空洞占据。这种情况最常见的发生方式是反复追加大字符串或文档。也许这不是您的情况,因为在这种情况下,无论调用多少次GC.Collect()均无法压缩LOH,但是在您的情况下,似乎有所帮助。然而,这是我见过的大多数OutOfMemory异常的根源。
垃圾回收器不总是能够有效地工作的另一个场景是某些事物导致对象保持根引用。 一个例子是事件处理程序可能会阻止对象被回收。 解决这个问题的方法是确保每个 +=
操作都有相应的 -=
操作来取消订阅它。 但是,GC.Collect() 在这里不太可能有帮助 - 对象仍然在某个地方保持着引用,因此无法被回收。
希望这为您提供了解决首先需要使用GC.Collect()的根本问题的调查途径。 但如果没有,当然最好有一个可运行的程序而不是一个失败的程序。 在任何我使用GC.Collect()的地方,我都会确保代码有良好的文档记录,解释为什么需要它(否则会出现异常),以及重现它所需的确切步骤和数据,以便未来的程序员可以确定在何时安全地删除它。
GC.Collect()
时,它在30%的时间内无法正常工作,则这将优先考虑其他所有问题。GC.Collect()
的更深层次问题。”一般来说,不应该需要使用GC.Collect
。如果您的图像存在于非托管内存中,请确保适当使用GC.AddMemoryPressure
和GC.RemoveMemoryPressure
。
Dispose
able对象,或者在操作之前没有设置将被替换为null的成员值。以下是后者的示例:
GC.Collect
会影响(并冻结)整个进程。 - Luaan