.net 使用 GC.Collect() 有什么问题?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/118633/
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
What's so wrong about using GC.Collect()?
提问by Trap
Although I do understand the serious implications of playing with this function (or at least that's what I think), I fail to see why it's becoming one of these things that respectable programmers wouldn't ever use, even those who don't even know what it is for.
虽然我确实理解使用这个函数的严重影响(或者至少我是这么认为的),但我不明白为什么它会成为受人尊敬的程序员永远不会使用的东西之一,即使是那些甚至不知道的人它是做什么用的。
Let's say I'm developing an application where memory usage varies extremely depending on what the user is doing. The application life cycle can be divided into two main stages: editing and real-time processing. During the editing stage, suppose that billions or even trillions of objects are created; some of them small and some of them not, some may have finalizers and some may not, and suppose their lifetimes vary from a very few milliseconds to long hours. Next, the user decides to switch to the real-time stage. At this point, suppose that performance plays a fundamental role and the slightest alteration in the program's flow could bring catastrophic consequences. Object creation is then reduced to the minimum possible by using object pools and the such but then, the GC chimes in unexpectedly and throws it all away, and someone dies.
假设我正在开发一个应用程序,其中内存使用量因用户正在做什么而有很大差异。应用程序生命周期可以分为两个主要阶段:编辑和实时处理。在编辑阶段,假设创建了数十亿甚至数万亿个对象;其中有些很小,有些没有,有些可能有终结器,有些可能没有,假设它们的生命周期从几毫秒到几个小时不等。接下来,用户决定切换到实时阶段。在这一点上,假设性能起着根本性的作用,程序流程中最轻微的改变都可能带来灾难性的后果。然后通过使用对象池等将对象创建减少到最低限度,但随后,GC 意外地响起并将其全部丢弃,有人死了。
The question: In this case, wouldn't it be wise to call GC.Collect() before entering the second stage?
问题:在这种情况下,在进入第二阶段之前调用 GC.Collect() 不是明智的吗?
After all, these two stages never overlap in time with each other and all the optimization and statistics the GC could have gathered would be of little use here...
毕竟,这两个阶段在时间上永远不会相互重叠,GC 可以收集的所有优化和统计信息在这里几乎没有用......
Note: As some of you have pointed out, .NET might not be the best platform for an application like this, but that's beyond the scope of this question. The intent is to clarify whether a GC.Collect() call can improve an application's overall behaviour/performance or not. We all agree that the circumstances under which you would do such a thing are extremely rare but then again, the GC tries to guess and does it perfectly well most of the time, but it's still about guessing.
注意:正如你们中的一些人指出的那样,.NET 可能不是此类应用程序的最佳平台,但这超出了本问题的范围。目的是澄清 GC.Collect() 调用是否可以改善应用程序的整体行为/性能。我们都同意,在这种情况下你会做这样的事情是非常罕见的,但话又说回来,GC 尝试猜测并且在大多数情况下做得很好,但它仍然是猜测。
Thanks.
谢谢。
采纳答案by Jon Norton
Rule #1
Don't.
This is really the most important rule. It's fair to say that most usages of GC.Collect() are a bad idea and I went into that in some detail in the orginal posting so I won't repeat all that here. So let's move on to...
Rule #2
Consider calling GC.Collect() if some non-recurring event has just happened and this event is highly likely to have caused a lot of old objects to die.
A classic example of this is if you're writing a client application and you display a very large and complicated form that has a lot of data associated with it. Your user has just interacted with this form potentially creating some large objects... things like XML documents, or a large DataSet or two. When the form closes these objects are dead and so GC.Collect() will reclaim the memory associated with them...
规则1
别。
这确实是最重要的规则。公平地说,GC.Collect() 的大多数用法都是一个坏主意,我在原始帖子中详细介绍了这一点,因此我不会在这里重复所有内容。那么让我们继续...
规则#2
如果一些非重复事件刚刚发生,并且这个事件很可能导致许多旧对象死亡,请考虑调用 GC.Collect()。
一个典型的例子是,如果您正在编写一个客户端应用程序,并且您要显示一个非常大且复杂的表单,其中包含大量与之相关的数据。您的用户刚刚与这个表单进行了交互,可能会创建一些大对象……比如 XML 文档,或者一两个大的 DataSet。当表单关闭时,这些对象已死,因此 GC.Collect() 将回收与它们关联的内存......
So it sounds like this situation may fall under Rule #2, you know that there's a moment in time where a lot of old objects have died, and it's non-recurring. However, don't forget Rico's parting words.
所以听起来这种情况可能属于规则#2,您知道有一段时间许多旧对象已经死亡,并且不会再次发生。但是,不要忘记Rico的离别词。
Rule #1 should trump Rule #2 without strong evidence.
没有强有力的证据,规则#1 应该胜过规则#2。
Measure, measure, measure.
测量,测量,再测量。
回答by Aaron Fischer
If you call GC.Collect() in production code you are essentially declaring that you know more then the authors of the GC. That may be the case. However it's usually not, and therefore strongly discouraged.
如果您在生产代码中调用 GC.Collect(),您实际上是在声明您比 GC 的作者了解更多。情况可能是这样。然而,它通常不是,因此强烈建议不要这样做。
回答by Dib
So how about when you are using COM objects like MS Word or MS Excel from .NET? Without calling GC.Collectafter releasing the COM objects we have found that the Word or Excel application instances still exist.
那么当您使用来自 .NET 的 MS Word 或 MS Excel 等 COM 对象时呢?GC.Collect释放COM对象后没有调用我们发现Word或Excel应用程序实例仍然存在。
In fact the code we use is:
实际上我们使用的代码是:
Utils.ReleaseCOMObject(objExcel)
' Call the Garbage Collector twice. The GC needs to be called twice in order to get the
' Finalizers called - the first time in, it simply makes a list of what is to be finalized,
' the second time in, it actually does the finalizing. Only then will the object do its
' automatic ReleaseComObject. Note: Calling the GC is a time-consuming process,
' but one that may be necessary when automating Excel because it is the only way to
' release all the Excel COM objects referenced indirectly.
' Ref: http://www.informit.com/articles/article.aspx?p=1346865&seqNum=5
' Ref: http://support.microsoft.com/default.aspx?scid=KB;EN-US;q317109
GC.Collect()
GC.WaitForPendingFinalizers()
GC.Collect()
GC.WaitForPendingFinalizers()
So would that be an incorrect use of the garbage collector? If so how do we get the Interop objects to die? Also if it isn't meant to be used like this, why is the GC's Collectmethod even Public?
那么这会是垃圾收集器的错误使用吗?如果是这样,我们如何让 Interop 对象消亡?此外,如果它不打算像这样使用,为什么GC'sCollect方法甚至Public?
回答by Jason Short
Well, the GC is one of those things I have a love / hate relationship with. We have broken it in the pastthrough VistaDB and blogged about it. They have fixed it, but it takes a LONG time to get fixes from them on things like this.
好吧,GC 是我爱恨交加的事物之一。我们过去曾通过 VistaDB破解它并在博客中介绍过它。他们已经修复了它,但需要很长时间才能从他们那里获得关于此类问题的修复。
The GC is complex, and a one size fits all approach is very, very hard to pull off on something this large. MS has done a fairly good job of it, but it is possible to fool the GC at times.
GC 很复杂,而且一刀切的方法很难在这么大的事情上实现。MS 在这方面做得相当不错,但有时可能会欺骗 GC。
In general you should not add a Collectunless you know for a fact you just dumped a ton of memory and it will go to a mid life crisisif the GC doesn't get it cleaned up now.
一般来说,你不应该添加 a ,Collect除非你知道你刚刚倾倒了大量内存,如果 GC 现在不清理它,它将进入中年危机。
You can screw up the entire machine with a series of bad GC.Collectstatements. The need for a collect statement almost always points to a larger underlying error. The memory leak usually has to do with references and a lack of understanding to how they work. Or using of the IDisposableon objects that don't need it and putting a much higher load on the GC.
你可以用一系列糟糕的GC.Collect陈述把整个机器搞砸。需要 collect 语句几乎总是指向更大的潜在错误。内存泄漏通常与引用有关,并且对它们的工作方式缺乏了解。或者使用IDisposable不需要它的对象并给 GC 带来更高的负载。
Watch closely the % of time spent in GC through the system performance counters. If you see your app using 20% or more of its time in the GC you have serious object management issues (or an abnormal usage pattern). You want to always minimize the time the GC spends because it will speed up your entire app.
通过系统性能计数器密切观察 GC 花费的时间百分比。如果您看到您的应用程序在 GC 中使用了 20% 或更多的时间,则您存在严重的对象管理问题(或异常使用模式)。您希望始终尽量减少 GC 花费的时间,因为它会加速您的整个应用程序。
It is also important to note that the GC is different on servers than workstations. I have seen a number of small difficult to track down problems with people not testing both of them (or not even aware that their are two of them).
同样重要的是要注意服务器上的 GC 与工作站上的不同。我见过一些难以追踪的小问题,人们没有测试它们(或者甚至不知道它们是其中的两个)。
And just to be as full in my answer as possible you should also test under Mono if you are targeting that platform as well. Since it is a totally different implementation it may experience totally different problems that the MS implementation.
为了尽可能完整地回答我的问题,如果您也针对该平台,您还应该在 Mono 下进行测试。由于它是一个完全不同的实现,它可能会遇到与 MS 实现完全不同的问题。
回答by rjohnston
There are situations where it's useful, but in general it should be avoided. You could compare it to GOTO, or riding a moped: you do it when you need to, but you don't tell your friends about it.
在某些情况下它很有用,但通常应该避免它。您可以将其与 GOTO 或骑轻便摩托车进行比较:您可以在需要时这样做,但不会告诉您的朋友。
回答by TheZenker
From my experience it has never been advisable to make a call to GC.Collect() in production code. In debugging, yes, it has it's advantages to help clarify potential memory leaks. I guess my fundamental reason is that the GC has been written and optimized by programmers much smarter then I, and if I get to a point that I feel I need to call GC.Collect() it is a clue that I have gone off path somewhere. In your situation it doesn't sound like you actually have memory issues, just that you are concerned what instability the collection will bring to your process. Seeing that it will not clean out objects still in use, and that it adapts very quickly to both rising and lowering demands, I would think you will not have to worry about it.
根据我的经验,在生产代码中调用 GC.Collect() 从来都是不可取的。在调试中,是的,它具有帮助澄清潜在内存泄漏的优势。我想我的根本原因是 GC 是由比我聪明得多的程序员编写和优化的,如果我觉得我需要调用 GC.Collect() 这就是我偏离路径的线索某处。在您的情况下,听起来您实际上并没有内存问题,只是您担心集合会给您的过程带来什么不稳定性。看到它不会清除仍在使用的对象,并且它可以非常快速地适应上升和下降的需求,我认为您不必担心。
回答by TraumaPony
One of the biggest reasons to call GC.Collect() is when you have just performed a significant event which creates lots of garbage, such as what you describe. Calling GC.Collect() can be a good idea here; otherwise, the GC may not understand that it was a 'one time' event.
调用 GC.Collect() 的最大原因之一是当您刚刚执行了一个会产生大量垃圾的重要事件时,例如您所描述的。在这里调用 GC.Collect() 可能是个好主意;否则,GC 可能不明白这是一个“一次性”事件。
Of course, you should profile it, and see for yourself.
当然,您应该对其进行概要分析,并亲自查看。
回答by wnoise
Well, obviously you should not write code with real-time requirements in languages with non-real-time garbage collection.
好吧,显然您不应该使用具有非实时垃圾收集功能的语言编写具有实时要求的代码。
In a case with well-defined stages, there is no problem with triggering the garbage-collector. But this case is extremely rare. The problem is that many developers are going to try to use this to paper-over problems in a cargo-cult style, and adding it indiscriminately will cause performance problems.
在具有明确定义的阶段的情况下,触发垃圾收集器没有问题。但这种情况极为罕见。问题在于,许多开发人员将尝试使用它来以一种狂热的方式来解决问题,并且不加选择地添加它会导致性能问题。
回答by Ta01
Calling GC.Collect() forces the CLR to do a stack walk to see if each object can be truely be released by checking references. This will affect scalability if the number of objects is high, and has also been known to trigger garbage collection too often. Trust the CLR and let the garbage collector run itself when appropriate.
调用 GC.Collect() 会强制 CLR 进行堆栈遍历,以通过检查引用来查看是否可以真正释放每个对象。如果对象数量很多,这将影响可伸缩性,并且已知会过于频繁地触发垃圾收集。信任 CLR 并让垃圾收集器在适当的时候自行运行。
回答by dale
Creating images in a loop - even if you call dispose, the memory is not recovered. Garbage collect every time. I went from 1.7GB memory on my photo processing app to 24MB and performance is excellent.
在循环中创建图像 - 即使您调用 dispose,内存也不会恢复。每次都收集垃圾。我的照片处理应用程序的内存从 1.7GB 增加到 24MB,性能非常好。
There are absolutely time that you need to call GC.Collect.
您绝对有时间需要调用 GC.Collect。

