.net 什么';使用GC.Collect()有什么不对?

.net 什么';使用GC.Collect()有什么不对?,.net,performance,memory-management,garbage-collection,.net,Performance,Memory Management,Garbage Collection,虽然我确实理解使用这个函数的严重影响(或者至少我是这么认为的),但我不明白为什么它会成为值得尊敬的程序员永远不会使用的东西之一,即使是那些甚至不知道它的用途的人 比方说,我正在开发一个应用程序,其中内存使用情况因用户所做的事情而变化极大。应用程序生命周期可分为两个主要阶段:编辑和实时处理。在编辑阶段,假设创建了数十亿甚至万亿个对象;它们有些小,有些不小,有些可能有终结器,有些可能没有,假设它们的生命周期从几毫秒到几小时不等。接下来,用户决定切换到实时阶段。在这一点上,假设性能起着根本性的作用,程

虽然我确实理解使用这个函数的严重影响(或者至少我是这么认为的),但我不明白为什么它会成为值得尊敬的程序员永远不会使用的东西之一,即使是那些甚至不知道它的用途的人


比方说,我正在开发一个应用程序,其中内存使用情况因用户所做的事情而变化极大。应用程序生命周期可分为两个主要阶段:编辑和实时处理。在编辑阶段,假设创建了数十亿甚至万亿个对象;它们有些小,有些不小,有些可能有终结器,有些可能没有,假设它们的生命周期从几毫秒到几小时不等。接下来,用户决定切换到实时阶段。在这一点上,假设性能起着根本性的作用,程序流程中的任何细微变化都可能带来灾难性的后果。然后,通过使用对象池和类似的方法将对象创建减少到尽可能小的程度,但随后,GC意外地插话并将其全部丢弃,导致有人死亡

问题:在这种情况下,在进入第二阶段之前调用GC.Collect()是否明智

毕竟,这两个阶段不会在时间上相互重叠,GC可以收集的所有优化和统计数据在这里几乎没有用处

注意:正如你们中的一些人所指出的,.NET可能不是这种应用程序的最佳平台,但这超出了这个问题的范围。其目的是澄清GC.Collect()调用是否可以改善应用程序的总体行为/性能。我们都同意,在这种情况下,你会做这样的事情是极为罕见的,但话说回来,GC尝试猜测,并且在大多数情况下都做得很好,但仍然是猜测


谢谢。

我认为您对该场景的看法是正确的,但我不确定API是否正确


Microsoft表示,在这种情况下,您应该向GC发出提示,提示它应该很快执行收集。

显然,您不应该使用具有非实时垃圾收集功能的语言编写具有实时要求的代码


在具有定义良好的阶段的情况下,触发垃圾收集器没有问题。但这种情况极为罕见。问题是,许多开发人员将尝试使用它以cargo cult的方式来掩盖问题,不加区分地添加它将导致性能问题。

在某些情况下,它是有用的,但通常应该避免。你可以把它比作GOTO,或者骑摩托车:你可以在需要的时候这样做,但你不会告诉你的朋友。

根据我的经验,在生产代码中调用GC.Collect()从来都不是明智之举。在调试中,是的,它有助于澄清潜在的内存泄漏。 我想我的根本原因是,GC是由比我聪明得多的程序员编写和优化的,如果我到了需要调用GC.Collect()的地步,这就表明我已经偏离了方向。
在您的情况下,听起来您并不是真的有内存问题,只是您关心的是收集会给您的进程带来什么样的不稳定性。鉴于它不会清理仍在使用的物体,而且它能很快地适应不断上升和下降的需求,我认为你不必担心它

总之,您可以分析应用程序,并查看这些附加集合如何影响事情。不过我建议你远离它,除非你打算做个人简介。GC的设计目的是照顾自己,随着运行时的发展,它们可能会提高效率。您不希望有一堆代码挂在周围,可能会把工作搞得一团糟,无法利用这些改进。使用foreach而不是for有一个类似的论点,那就是,将来的改进可以添加到foreach中,并且您的代码不必更改以利用它

如果在生产代码中调用GC.Collect(),实际上就是声明您比GC的作者了解更多。可能是这样。但是通常不是这样,因此强烈反对。

调用GC.Collect()强制CLR进行堆栈遍历,以查看是否可以通过检查引用来真正释放每个对象。如果对象的数量很高,这将影响可伸缩性,并且已知会经常触发垃圾收集。信任CLR,并在适当的时候让垃圾收集器自己运行。

调用GC.Collect()的最大原因之一是,您刚刚执行了一个会产生大量垃圾的重要事件,如您所描述的。在这里调用GC.Collect()可能是个好主意;否则,GC可能无法理解这是一个“一次性”事件

当然,您应该对其进行分析,并亲自查看。

规则#1

不要

这真的是最重要的 规则。公平地说,大多数情况下 使用GC.Collect()是个坏主意 我在一篇文章中详细讨论了这一点 原来的帖子,所以我不会重复 所有这些都在这里。那么让我们继续讨论

规则#2

考虑调用GC.Collect() 非经常性事件刚刚发生 而这一事件极有可能 已经造成了很多旧物体的损坏 死

一个典型的例子是如果你 编写客户端应用程序和 显示一个非常大且复杂的 具有大量关联数据的窗体 用它。您的用户刚刚 可能与此表单交互 正在创建一些大型对象。。。东西 如XML文档或大型数据集 一两个。当窗体关闭这些 对象是死的,因此GC.Collect() 将回收关联的内存 和他们一起

因此,你知道,这种情况听起来可能属于规则2
var obj = /* object utilizing the memory, in my case Form itself */
GC.Collect(GC.GetGeneration(obj ,GCCollectionMode.Optimized).