【发布时间】:2011-07-20 00:07:16
【问题描述】:
据我所知,CLR 会为您完成所有这些垃圾收集,但是否有理由手动调用 GC.Collect()?
是否在关闭文件、释放图像资源或非托管资源的情况下,应该立即调用GC.Collect() 快速清理未使用的内存?
【问题讨论】:
标签: c# .net garbage-collection
据我所知,CLR 会为您完成所有这些垃圾收集,但是否有理由手动调用 GC.Collect()?
是否在关闭文件、释放图像资源或非托管资源的情况下,应该立即调用GC.Collect() 快速清理未使用的内存?
【问题讨论】:
标签: c# .net garbage-collection
我只能想到GC.Collect() 可能有用的两种情况:
在单元测试中。在进行一些测试之前和之后调用GC.Collect() 以查找潜在的内存泄漏。在这种情况下考虑使用GC.WaitForPendingFinalizers(),因为终结器在单独的线程中执行。这意味着具有终结器的类在调用 GC.Collect() 后不会立即释放所有资源。
在诸如 Windows 服务之类的长期存在的进程中存在很长的空闲时间。在它空闲之前致电GC.Collect()。原因:如果进程处于空闲状态,垃圾收集器不会启动,因此空闲期间不会释放未使用的内存。
GC.Collect() 不应以“立即快速清理未使用的内存”为目的而调用。强制释放内存并不能抵消主动垃圾回收带来的整体性能。
【讨论】:
我唯一一次在不是专门比较两种或多种不同方法的内存使用情况的代码中使用它的情况如下:
在 Web 应用程序中(因此是长期运行的),有一些非常大的集合,通常每天最多重新构建几次,而且频率通常要低得多。
该集合中的几个对象将是等效的,因此可以通过将对一个此类对象的引用替换为对另一个对象的引用来节省大量内存(在构建集合之后是只读的,因此别名涉及是安全的)。所以首先会构建集合,但随后会减小它的大小,从而杀死许多对象。
这意味着每秒销毁的对象数量突然激增,至少在几个小时内不会再次发生这种情况。因此,GC 无法正确判断所需的收集量,并且将需要该内存来构建第二个大型收集。因此,每千次清理操作执行一次手动收集确实对性能产生了积极影响(有时足以让应用程序在第三次收集时崩溃,使其变得可靠)。
进行了大量测量以确保它在这种情况下确实是有益的。
使这项工作受益的两个因素是:
如果这两个都不是真的,手动调用就没有必要了。如果没有大量的对象死亡,那就没有意义了,如果在应用程序的生命周期中它不是罕见的,GC 就会自我调整以应对。
【讨论】:
我通常使用GC.Collect() 将堆置于最广为人知的状态。例如,在进行基准测试时,您需要确保从已知状态开始每次运行,GC.Collect() 可以帮助您解决此问题。
它不应该用于处置非托管资源——为此您应该使用using 或手动调用Dispose。
【讨论】:
是否在关闭文件、释放图像资源或非托管资源的情况下,应该立即调用 GC.Collect() 快速清理未使用的内存?
不,不是真的。这通常通过IDisposable 处理。
直接调用GC.Dispose() 的理由很少,而且这样做通常会造成很大的危害,因为它会干扰 .NET 中 GC 的内部启发式。然而,当它有用时,很少出现。
例如,如果您有一个使用大型对象图的罕见操作,并且您知道之后您将“空闲”,您可能想要调用@987654323 @ 之后立即释放对象使用的内存。话虽如此,这通常仍然最好由系统来处理。
在大多数情况下,我发现GC.Collect() 最有用的场景是用于调试。它可以帮助您确保没有泄漏,因为它允许您强制进行完整的 Gen2 收集。
【讨论】: