【问题标题】:Reasons why one should not call the garbage collector directly不应该直接调用垃圾收集器的原因
【发布时间】:2010-06-16 10:16:11
【问题描述】:

我目前正在为我的公司写一篇论文,关于如何避免直接从代码中调用垃圾收集器(例如在使用 COM 对象时)。

我知道这是一种不好的做法,应该只在极少数情况下考虑,但我似乎无法找到一种方法来说明为什么应该避免它。而且我不想依赖“GC比你聪明”的原则(即使这是事实:-))

那么你能告诉我一些关于为什么你认为应该避免直接调用垃圾收集器的线索吗? (性能影响?)或者如果你有关于这个特定主题的链接,它们会非常有帮助。

提前致谢!

编辑:到目前为止,您提供的所有回答都非常有帮助。由于我无法验证所有人(或者我可以吗?),我该怎么办?制作社区维基?

【问题讨论】:

    标签: .net garbage-collection


    【解决方案1】:

    主要原因是程序在 GC 中执行完整收集的时间超过了必要的时间。

    鉴于这是一种更容易获得更好性能的情况,对我来说似乎很简单!

    注意。玩 COM 对象时,直接调用 GC 不太可能解决您的问题。如果 COM 对象处于闲置状态,则它们的引用计数不为零,并且任何额外的 GC 调用都无法解决此问题。

    【讨论】:

    • 但另一方面,有些 COM 对象即使在 COM 对象的引用计数为 0 后也不会消失。我已经看到 Excel COM 对象发生了这种情况。
    • Vinko,这正是我文档中的示例。但是可以在不显式调用 G.C. 的情况下删除所有引用
    • 是的,Excel 的问题通常是您应用程序创建了对对象的引用而没有实际保留引用(例如,通过执行类似Sheets(0).SomeSheetMethod 的操作,它创建了一个不属于保留,因此不能显式释放)。
    • 这正是我在我的文档中所解释的内容 ho1 :-) 因此,一旦您了解这一点,就无需致电 G.C.。你知道这种行为是所有 COM 对象共有的,还是只有 Excel 创建的那些?
    【解决方案2】:

    通常的性能论点是这样运行的:

    Generational GC 速度很快,因为它们依赖于许多分配的对象是短暂的(只要可以到达,对象就是“活”的;GC 的目的是检测“死”对象并回收它们记忆)。这意味着对象可以积累在一个特殊的区域(“年轻一代”); GC 在该区域已满时运行,并清除活动对象,将它们(“物理上”)移动到老年代。在大多数分代 GC 中,此操作意味着暂停(“stop-the-world”),这是可以容忍的,因为它很短(年轻代的大小有限)。在年轻代收集期间世界暂停的事实允许有效处理年轻对象(即,在年轻对象字段中读取或写入引用只是内存访问,无需考虑来自 GC 线程的并发访问或增量标记和扫描)。

    一个年轻代,像我上面描述的那样运行一个集合,是高效的,因为当年轻代被收集时,其中的大部分对象已经死了,所以它们不会产生额外的成本。年轻代的最佳大小是在最坏情况(所有年轻对象都活着,这意味着最大的暂停时间)和平均效率(当年轻代更大时,更多对象有时间死去之前)之间的权衡。收集,从而降低了 GC 的平均成本)。

    手动运行 GC 类似于缩短年轻代。这意味着更多的年轻对象将被提升到老年代,从而增加了年轻代的收集成本(必须清除更多的对象)老年代的收集成本(处理更多旧对象)。

    【讨论】:

      【解决方案3】:

      它会影响性能,因为需要停止所有线程才能执行收集。之后它需要确定什么是使用的,什么不是等等......

      所有这些都需要时间,垃圾收集器只有在确定利大于弊时才会起作用。

      当您自己调用 GC 时,您很可能只是过于频繁地调用它,这会增加在 GC 中花费的时间并减少在您的程序中花费的时间。

      【讨论】:

        【解决方案4】:

        如果您需要调用 GarbageCollector 以确保释放 COM 对象,这可能是一个好兆头,即您的开发人员不调用 Dispose 和/或不使用 using 在他们应该的时候。所以一个论点可能是它只是隐藏了错误的代码,而修复错误的代码会更好。

        【讨论】:

        • COM 对象不倾向于支持IDisposable,因此这不会直接成为解决方案。
        • @Daniel Earwicker:您误会了,我的意思是 COM 对象是非托管资源,您可能需要在 Dispose 方法中以某种方式或其他方式(可能是 ReleaseComObject)进行清理.如果使用 COM 对象的那个类的开发者已经在 Dispose 中编写了它来清理,那么该类的调用者应该调用Dispose 或使用using
        • 不,我明白了。这就是为什么我说直接。 :)
        • @Daniel:那么我理解错了,所以我至少部分正确,其中一个用途被误解了。
        猜你喜欢
        • 2021-11-19
        • 1970-01-01
        • 1970-01-01
        • 2010-12-15
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2018-12-30
        • 1970-01-01
        相关资源
        最近更新 更多