当前位置:  开发笔记 > 编程语言 > 正文

在C#中强制垃圾收集的最佳实践

如何解决《在C#中强制垃圾收集的最佳实践》经验,为你挑选了10个好方法。

根据我的经验,似乎大多数人会告诉你强制垃圾收集是不明智的,但在某些情况下,你正在使用大型对象,这些对象并不总是在0代收集,但内存是一个问题,是它可以强制收集?这样做有最好的做法吗?



1> Mark Ingram..:

最佳做法是不强制进行垃圾回收.

根据MSDN:

"可以通过调用Collect来强制进行垃圾收集,但大多数情况下,这应该避免,因为它可能会产生性能问题."

但是,如果您可以可靠地测试代码以确认调用Collect()不会产生负面影响,那么请继续...

只是在不再需要时确保清理对象.如果您有自定义对象,请查看"using statement"和IDisposable接口.

这个链接在释放内存/垃圾收集等方面有一些很好的实用建议:

http://msdn.microsoft.com/en-us/library/66x5fx1b.aspx


如果您的对象指向非托管内存,您可以通过GC.AddMemoryPressure Api(http://msdn.microsoft.com/en-us/library/system.gc.addmemorypressure.aspx)了解垃圾收集器.这为垃圾收集器提供了有关系统的更多信息,而不会干扰收集算法.
此外,您可以设置不同的LatencyMode的http://msdn.microsoft.com/en-us/library/bb384202.aspx

2> Ian Ringrose..:

最佳做法是在大多数情况下不强制进行垃圾收集. (我所研究过的每个系统都强制进行垃圾收集,强调了如果解决问题就会消除强制垃圾收集的需要,并大大加快系统速度.)

在某些情况下,您可以了解有关内存使用情况的更多信息.在多用户应用程序或一次响应多个请求的服务中,这不可能成立.

但是在某些批处理类型处理中,您确实了解GC.例如,考虑一个应用程序.

在命令行上给出了文件名列表

处理单个文件,然后将结果写入结果文件.

处理文件时,会创建大量互连对象,在文件处理完成之前无法收集这些对象(例如,解析树)

在它处理的文件之间没有多少状态.

可能能够(经过仔细测试)测试后应该在处理完每个文件后强制执行完整的垃圾回收.

另一种情况是每隔几分钟醒来处理一些物品,并且在睡着时不保持任何状态的服务.然后在睡觉之前强制完整收集可能是值得的.

我唯一一次考虑强制收集的是当我知道最近创建了很多对象时,当前引用的对象非常少.

我宁愿有一个垃圾收集API,当我可以给它提示这种类型的东西,而不必强迫我自己的GC.

另见" Rico Mariani的表演花絮 "


打个比方:Playschool(系统)保持蜡笔(资源).根据孩子(任务)的数量和颜色的稀缺性,教师(.Net)决定如何在孩子之间分配和分享.当请求稀有颜色时,教师可以从池中分配或查找未使用的颜色.教师可以自行定期收集未使用的蜡笔(垃圾收集)以保持整洁(优化资源使用).通常,父母(程序员)无法预先确定最佳课堂蜡笔整理政策.一个孩子的预定午睡不太可能是干扰其他孩子着色的好时机.

3> Maxam..:

看看这样的方式 - 是更有效的抛出了厨房垃圾时,垃圾可以在10%或服用之前让它填补?

不要让它填满,你浪费时间往外走垃圾桶.这类似于GC线程运行时发生的情况 - 所有托管线程在运行时都被挂起.如果我没有弄错,GC线程可以在多个AppDomain之间共享,因此垃圾收集会影响所有这些.

当然,你可能会遇到一种情况,你不会很快就会在垃圾桶里添加任何东西 - 比方说,如果你要休假.然后,在外出之前把垃圾丢掉是个好主意.

这可能是迫使GC可以提供帮助的一次 - 如果您的程序空闲,则使用的内存不会被垃圾收集,因为没有分配.


如果你有一个婴儿,如果你离开它超过一分钟会死,而你只有一分钟处理垃圾,那么你想要每次做一点而不是一次.不幸的是,GC :: Collect()方法不是更快,你调用它的频率越高.因此,对于实时引擎,如果您不能只使用dispose机制并让GC汇集您的数据,那么您不应该使用托管系统 - 根据我的回答(可能在这个下面,大声笑).

4> denis philli..:

我认为Rico Mariani给出的例子很好:如果应用程序的状态发生重大变化,可能适合触发GC.例如,在文档编辑器中,可以在文档关闭时触发GC.


或者就在打开一个显示失败历史的大型连续对象之前,并且没有提高其粒度的有效分辨率.

5> 小智..:

编程中很少有一般指导方针是绝对的.有一段时间,当有人说'你做错了'时,他们只是在喷出一定量的教条.在C语言中,过去常担心自修改代码或线程,在GC语言中它强制GC或者阻止GC运行.

与大多数指南和良好的经验法则(以及良好的设计实践)一样,在极少数情况下,围绕既定规范工作是有意义的.你必须非常确定你理解这个案子,你的案件确实需要废除普通的做法,并且你了解你可能导致的风险和副作用.但是有这样的情况.

编程问题种类繁多,需要灵活的方法.我已经看到了在垃圾收集语言中阻止GC以及触发它而不是等待它自然发生的地方的情况.95%的时间,其中任何一个都是没有正确处理问题的路标.但是在20年的一次,可能会有一个有效的案例.



6> Kon..:

我已经学会了不要试图超越垃圾收集.话虽如此,我只是using在处理非托管资源(如文件I/O或数据库连接)时坚持使用关键字.


编译器?编译器与GC有什么关系?:)

7> Michael Stum..:

不确定它是否是最佳实践,但是当在循环中处理大量图像时(即创建和处理大量图形/图像/位图对象),我经常让GC.Collect.

我想我在某处看到GC只在程序(大部分)空闲时运行,而不是在密集循环的中间运行,因此看起来像手动GC可能有意义的区域.


如果没有其他进程需要,则不会浪费100兆的RAM.它给你带来了不错的性能提升:-P
当第0代达到某个阈值(例如1MB)时,GC会在内存分配时触发,而不是在"某些东西空闲"时触发.否则,您可以通过简单地分配并立即丢弃对象来在循环中结束OutOfMemoryException.

8> 小智..:

我最近遇到的一个需要手动调用的情况GC.Collect()是处理大型C++对象,这些对象包含在很小的托管C++对象中,而这些对象又是从C#访问的.

垃圾收集器从未被调用,因为使用的托管内存量可以忽略不计,但是使用的非托管内存量非常大.手动调用Dispose()对象需要我跟踪自己何时不再需要对象,而调用GC.Collect()将清理任何不再被引用的对象.....


解决这个问题的更好方法是在构造函数中调用`GC.AddMemoryPressure(ApproximateSizeOfUnmanagedResource)`,然后在终结器中调用`GC.RemoveMemoryPressure(addedSize)`.这样,垃圾收集器将自动运行,同时考虑到可以收集的非托管结构的大小.http://stackoverflow.com/questions/1149181/what-is-the-point-of-using-gc-addmemorypressure-with-an-unmanaged-resource
最好的方法是使用Using结构.尝试/最后.目的是一个麻烦

9> Mitchel Sell..:

我认为你已经列出了最佳实践,除非真的需要,否则不要使用它.我强烈建议您更详细地查看您的代码,如果需要首先使用分析工具来回答这些问题.

    您的代码中是否有一些声明项目范围超出需要的内容

    内存使用量是否真的太高了

    比较使用GC.Collect()之前和之后的性能,看它是否真的有帮助.



10> Morgan Cheng..:

假设您的程序没有内存泄漏,对象累积且无法在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.

推荐阅读
乐韵答题
这个屌丝很懒,什么也没留下!
DevBox开发工具箱 | 专业的在线开发工具网站    京公网安备 11010802040832号  |  京ICP备19059560号-6
Copyright © 1998 - 2020 DevBox.CN. All Rights Reserved devBox.cn 开发工具箱 版权所有