在 C# 中强制垃圾回收的最佳实践
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/233596/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Best Practice for Forcing Garbage Collection in C#
提问by Echostorm
In my experience it seems that most people will tell you that it is unwise to force a garbage collection but in some cases where you are working with large objects that don't always get collected in the 0 generation but where memory is an issue, is it ok to force the collect? Is there a best practice out there for doing so?
根据我的经验,似乎大多数人会告诉您强制进行垃圾回收是不明智的,但在某些情况下,您正在处理的大对象并不总是在 0 代中被回收,但内存是一个问题,是可以强制收集吗?有没有这样做的最佳实践?
采纳答案by Mark Ingram
The best practise is to not force a garbage collection.
最佳做法是不要强制进行垃圾回收。
According to MSDN:
根据 MSDN:
"It is possible to force garbage collection by calling Collect, but most of the time, this should be avoided because it may create performance issues. "
“可以通过调用 Collect 来强制进行垃圾回收,但大多数情况下,应该避免这样做,因为它可能会造成性能问题。”
However, if you can reliably test your code to confirm that calling Collect() won't have a negative impact then go ahead...
但是,如果您可以可靠地测试您的代码以确认调用 Collect() 不会产生负面影响,那么请继续...
Just try to make sure objects are cleaned up when you no longer need them. If you have custom objects, look at using the "using statement" and the IDisposable interface.
只需确保在不再需要对象时将其清理干净即可。如果您有自定义对象,请查看使用“using 语句”和 IDisposable 接口。
This link has some good practical advice with regards to freeing up memory / garbage collection etc:
这个链接有一些关于释放内存/垃圾收集等很好的实用建议:
回答by Kon
I've learned to not try to outsmart the garbage collection. With that said, I just stick to using using
keyword when dealing with unmanaged resources like file I/O or database connections.
我已经学会了不要试图超越垃圾收集。话虽如此,using
在处理文件 I/O 或数据库连接等非托管资源时,我只是坚持使用关键字。
回答by Michael Stum
Not sure if it is a best practice, but when working with large amounts of images in a loop (i.e. creating and disposing a lot of Graphics/Image/Bitmap objects), i regularly let the GC.Collect.
不确定这是否是最佳实践,但是在循环中处理大量图像时(即创建和处理大量 Graphics/Image/Bitmap 对象),我经常让 GC.Collect。
I think I read somewhere that the GC only runs when the program is (mostly) idle, and not in the middle of a intensive loop, so that could look like an area where manual GC could make sense.
我想我在某处读到 GC 只在程序(大部分)空闲时运行,而不是在密集循环的中间,所以这看起来像是手动 GC 有意义的区域。
回答by Mitchel Sellers
I think you already listed the best practice and that is NOT to use it unless REALLY necessary. I would strongly recommend looking at your code in more detail, using profiling tools potentially if needed to answer these questions first.
我认为您已经列出了最佳实践,除非真的有必要,否则不要使用它。我强烈建议更详细地查看您的代码,如果需要首先使用分析工具来回答这些问题。
- Do you have something in your code that is declaring items at a larger scope than needed
- Is the memory usage really too high
- Compare performance before and after using GC.Collect() to see if it really helps.
- 您的代码中是否有一些东西在比需要的范围内声明了更大的范围内的项目
- 内存占用真的太高了吗
- 比较使用 GC.Collect() 之前和之后的性能,看看它是否真的有帮助。
回答by liggett78
Large objects are allocated on LOH (large object heap), not on gen 0. If you're saying that they don't get garbage-collected with gen 0, you're right. I believe they are collected only when the full GC cycle (generations 0, 1 and 2) happens.
大对象在 LOH(大对象堆)上分配,而不是在 gen 0 上。如果您说它们不会在 gen 0 中被垃圾收集,那么您是对的。我相信只有在完整的 GC 周期(第 0、1 和 2 代)发生时才会收集它们。
That being said, I believe on the other side GC will adjust and collect memory more aggressively when you work with large objects and the memory pressure is going up.
话虽如此,我相信另一方面,当您处理大对象并且内存压力上升时,GC 会更积极地调整和收集内存。
It is hard to say whether to collect or not and in which circumstances. I used to do GC.Collect() after disposing of dialog windows/forms with numerous controls etc. (because by the time the form and its controls end up in gen 2 due to creating many instances of business objects/loading much data - no large objects obviously), but actually didn't notice any positive or negative effects in the long term by doing so.
收不收,什么情况下,很难说。我曾经在处理具有大量控件等的对话框窗口/表单等之后执行 GC.Collect() (因为当表单及其控件由于创建许多业务对象实例/加载大量数据而最终在第 2 代中结束时 - 没有显然是大型物体),但实际上并没有注意到这样做从长远来看有任何积极或消极的影响。
回答by Morgan Cheng
Suppose your program doesn't have memory leakage, objects accumulates and cannot be GC-ed in Gen 0 because: 1) They are referenced for long time so get into Gen1 & Gen2; 2) They are large objects (>80K) so get into LOH (Large Object Heap). And LOH doesn't do compacting as in Gen0, Gen1 & Gen2.
假设您的程序没有内存泄漏,对象累积并且无法在 Gen 0 中进行 GC-ed,因为: 1)它们被引用了很长时间,因此进入 Gen1 & Gen2;2)它们是大对象(> 80K)所以进入LOH(大对象堆)。而且 LOH 不像 Gen0、Gen1 和 Gen2 那样进行压缩。
Check the performance counter of ".NET Memory" can you can see that the 1) problem is really not a problem. Generally, every 10 Gen0 GC will trigger 1 Gen1 GC, and every 10 Gen1 GC will trigger 1 Gen2 GC. Theoretically, GC1 & GC2 can never be GC-ed if there is no pressure on GC0 (if the program memory usage is really wired). It never happens to me.
检查“.NET Memory”的性能计数器可以看到1)问题确实不是问题。一般每10次Gen0 GC会触发1次Gen1 GC,每10次Gen1 GC会触发1次Gen2 GC。理论上,如果 GC0 没有压力(如果程序内存使用真的连线的话),GC1 & GC2 永远不会被 GC-ed。它永远不会发生在我身上。
For problem 2), you can check ".NET Memory" performance counter to verify whether LOH is getting bloated. If it is really a issue to your problem, perhaps you can create a large-object-pool as this blog suggests http://blogs.msdn.com/yunjin/archive/2004/01/27/63642.aspx.
对于问题 2),您可以检查“.NET Memory”性能计数器以验证 LOH 是否变得臃肿。如果这确实是您的问题的一个问题,也许您可以创建一个大型对象池,因为该博客建议http://blogs.msdn.com/yunjin/archive/2004/01/27/63642.aspx。
回答by Morgan Cheng
One more thing, triggering GC Collect explicitly may NOT improve your program's performance. It is quite possible to make it worse.
还有一件事,显式触发 GC 收集可能不会提高程序的性能。很可能让它变得更糟。
The .NET GC is well designed and tuned to be adaptive, which means it can adjust GC0/1/2 threshold according to the "habit" of your program memory usage. So, it will be adapted to your program after some time running. Once you invoke GC.Collect explicitly, the thresholds will be reset! And the .NET has to spent time to adapt to your program's "habit" again.
.NET GC 经过精心设计和调整,具有自适应性,这意味着它可以根据程序内存使用的“习惯”调整 GC0/1/2 阈值。因此,它会在运行一段时间后适应您的程序。一旦您显式调用 GC.Collect,阈值将被重置!.NET 不得不花时间重新适应你的程序的“习惯”。
My suggestion is always trust .NET GC. Any memory problem surfaces, check ".NET Memory" performance counter and diagnose my own code.
我的建议是始终信任 .NET GC。出现任何内存问题,检查“.NET 内存”性能计数器并诊断我自己的代码。
回答by Maxam
Look at it this way - is it more efficient to throw out the kitchen garbage when the garbage can is at 10% or let it fill up before taking it out?
这样看——垃圾桶是10%的时候把厨房垃圾扔掉还是先装满再拿出来效率更高?
By not letting it fill up, you are wasting your time walking to and from the garbage bin outside. This analogous to what happens when the GC thread runs - all the managed threads are suspended while it is running. And If I am not mistaken, the GC thread can be shared among multiple AppDomains, so garbage collection affects all of them.
如果不让它填满,您就是在浪费时间往返于外面的垃圾箱。这类似于 GC 线程运行时发生的情况——所有托管线程在运行时都被挂起。如果我没记错的话,GC 线程可以在多个 AppDomain 之间共享,因此垃圾回收会影响所有这些。
Of course, you might encounter a situation where you won't be adding anything to the garbage can anytime soon - say, if you're going to take a vacation. Then, it would be a good idea to throw out the trash before going out.
当然,您可能会遇到这样的情况,即您不会在短期内向垃圾桶添加任何东西 - 例如,如果您要休假。那么,出门前把垃圾扔掉是个好主意。
This MIGHT be one time that forcing a GC can help - if your program idles, the memory in use is not garbage-collected because there are no allocations.
这可能是强制 GC 可以提供帮助的一次 - 如果您的程序空闲,则使用中的内存不会被垃圾收集,因为没有分配。
回答by Orion Edwards
However, if you can reliably test your code to confirm that calling Collect() won't have a negative impact then go ahead...
但是,如果您可以可靠地测试您的代码以确认调用 Collect() 不会产生负面影响,那么请继续...
IMHO, this is similar to saying "If you can prove that your program will never have any bugs in the future, then go ahead..."
恕我直言,这类似于说“如果你能证明你的程序将来永远不会有任何错误,那么继续......”
In all seriousness, forcing the GC is useful for debugging/testing purposes. If you feel like you need to do it at any other times, then either you are mistaken, or your program has been built wrong. Either way, the solution is not forcing the GC...
严肃地说,强制 GC 对于调试/测试目的很有用。如果你觉得你需要在任何其他时间这样做,那么要么你错了,要么你的程序构建错了。无论哪种方式,解决方案都不会强制GC ...
回答by denis phillips
I think the example given by Rico Marianiwas good: it may be appropriate to trigger a GC if there is a significant change in the application's state. For example, in a document editor it may be OK to trigger a GC when a document is closed.
我认为Rico Mariani给出的例子很好:如果应用程序的状态发生重大变化,触发 GC 可能是合适的。例如,在文档编辑器中,当文档关闭时触发 GC 可能是可以的。