根据我的经验,似乎大多数人会告诉你强制垃圾收集是不明智的,但在某些情况下,你正在使用大型对象,这些对象并不总是在0代收集,但内存是一个问题,是它可以强制收集?这样做有最好的做法吗?
最佳做法是不强制进行垃圾回收.
根据MSDN:
"可以通过调用Collect来强制进行垃圾收集,但大多数情况下,这应该避免,因为它可能会产生性能问题."
但是,如果您可以可靠地测试代码以确认调用Collect()不会产生负面影响,那么请继续...
只是在不再需要时确保清理对象.如果您有自定义对象,请查看"using statement"和IDisposable接口.
这个链接在释放内存/垃圾收集等方面有一些很好的实用建议:
http://msdn.microsoft.com/en-us/library/66x5fx1b.aspx
最佳做法是在大多数情况下不强制进行垃圾收集. (我所研究过的每个系统都强制进行垃圾收集,强调了如果解决问题就会消除强制垃圾收集的需要,并大大加快系统速度.)
在某些情况下,您可以了解有关内存使用情况的更多信息.在多用户应用程序或一次响应多个请求的服务中,这不可能成立.
但是在某些批处理类型处理中,您确实了解GC.例如,考虑一个应用程序.
在命令行上给出了文件名列表
处理单个文件,然后将结果写入结果文件.
处理文件时,会创建大量互连对象,在文件处理完成之前无法收集这些对象(例如,解析树)
在它处理的文件之间没有多少状态.
您可能能够(经过仔细测试)测试后应该在处理完每个文件后强制执行完整的垃圾回收.
另一种情况是每隔几分钟醒来处理一些物品,并且在睡着时不保持任何状态的服务.然后在睡觉之前强制完整收集可能是值得的.
我唯一一次考虑强制收集的是当我知道最近创建了很多对象时,当前引用的对象非常少.
我宁愿有一个垃圾收集API,当我可以给它提示这种类型的东西,而不必强迫我自己的GC.
另见" Rico Mariani的表演花絮 "
看看这样的方式 - 是更有效的抛出了厨房垃圾时,垃圾可以在10%或服用之前让它填补?
不要让它填满,你浪费时间往外走垃圾桶.这类似于GC线程运行时发生的情况 - 所有托管线程在运行时都被挂起.如果我没有弄错,GC线程可以在多个AppDomain之间共享,因此垃圾收集会影响所有这些.
当然,你可能会遇到一种情况,你不会很快就会在垃圾桶里添加任何东西 - 比方说,如果你要休假.然后,在外出之前把垃圾丢掉是个好主意.
这可能是迫使GC可以提供帮助的一次 - 如果您的程序空闲,则使用的内存不会被垃圾收集,因为没有分配.
我认为Rico Mariani给出的例子很好:如果应用程序的状态发生重大变化,可能适合触发GC.例如,在文档编辑器中,可以在文档关闭时触发GC.
编程中很少有一般指导方针是绝对的.有一段时间,当有人说'你做错了'时,他们只是在喷出一定量的教条.在C语言中,过去常担心自修改代码或线程,在GC语言中它强制GC或者阻止GC运行.
与大多数指南和良好的经验法则(以及良好的设计实践)一样,在极少数情况下,围绕既定规范工作是有意义的.你必须非常确定你理解这个案子,你的案件确实需要废除普通的做法,并且你了解你可能导致的风险和副作用.但是有这样的情况.
编程问题种类繁多,需要灵活的方法.我已经看到了在垃圾收集语言中阻止GC以及触发它而不是等待它自然发生的地方的情况.95%的时间,其中任何一个都是没有正确处理问题的路标.但是在20年的一次,可能会有一个有效的案例.
我已经学会了不要试图超越垃圾收集.话虽如此,我只是using
在处理非托管资源(如文件I/O或数据库连接)时坚持使用关键字.
不确定它是否是最佳实践,但是当在循环中处理大量图像时(即创建和处理大量图形/图像/位图对象),我经常让GC.Collect.
我想我在某处看到GC只在程序(大部分)空闲时运行,而不是在密集循环的中间运行,因此看起来像手动GC可能有意义的区域.
我最近遇到的一个需要手动调用的情况GC.Collect()
是处理大型C++对象,这些对象包含在很小的托管C++对象中,而这些对象又是从C#访问的.
垃圾收集器从未被调用,因为使用的托管内存量可以忽略不计,但是使用的非托管内存量非常大.手动调用Dispose()
对象需要我跟踪自己何时不再需要对象,而调用GC.Collect()
将清理任何不再被引用的对象.....
我认为你已经列出了最佳实践,除非真的需要,否则不要使用它.我强烈建议您更详细地查看您的代码,如果需要首先使用分析工具来回答这些问题.
您的代码中是否有一些声明项目范围超出需要的内容
内存使用量是否真的太高了
比较使用GC.Collect()之前和之后的性能,看它是否真的有帮助.
假设您的程序没有内存泄漏,对象累积且无法在Gen 0中进行GC编辑,因为:1)它们被长时间引用,因此进入Gen1和Gen2; 2)它们是大型物体(> 80K),因此进入LOH(大物体堆).并且LOH不像Gen0,Gen1和Gen2那样进行压缩.
检查".NET内存"的性能计数器,你可以看到1)问题确实不是问题.通常,每10个Gen0 GC将触发1个Gen1 GC,每10个Gen1 GC将触发1个Gen2 GC.理论上,如果GC0没有压力(如果程序存储器使用情况确实有线),GC1和GC2永远不能进行GC编辑.它永远不会发生在我身上.
对于问题2),您可以检查".NET Memory"性能计数器以验证LOH是否变得臃肿.如果它确实是您的问题的问题,也许您可以创建一个大对象池,因为这篇博客建议http://blogs.msdn.com/yunjin/archive/2004/01/27/63642.aspx.