【问题标题】:Use of Garbage Collection?使用垃圾收集?
【发布时间】:2011-03-10 02:00:46
【问题描述】:

我想知道当我们调用 Dispose() 方法时执行了什么操作。 Is Object 在 Dispose() 调用或 Dispose() 标记对象已准备好进行垃圾回收时快速释放所有资源。当我们将对象引用设置为 NULL 时会发生什么。实际上我在 .NET 2.0 中有 Windows 窗体应用程序。我想在经过一定时间后(例如 5 分钟后)调用垃圾收集器来收集所有未引用的对象。

【问题讨论】:

    标签: c# garbage-collection dispose


    【解决方案1】:

    Dispose 方法没有什么神奇之处,它与任何其他方法一样。调用 Dispose 方法不会在后台进行任何清理或更改对象的状态,它只是执行您在方法中放入的内容。它的特别之处在于它是在 IDisposable 接口中定义的,因此它是告诉对象清理其资源的标准方式。

    在 Dispose 方法中,对象应处理所有非托管资源,例如数据库连接和字体对象。

    当您释放一个对象时,您不必担心任何托管资源。像字节数组这样的结构完全由垃圾收集器处理,您可以在放手时将其留在对象中。你不需要设置任何对null的引用,当你不再使用一个对象时,垃圾收集器会找到最好的时间来删除它和它引用的任何对象。

    垃圾收集器通常在你不理会它时工作得最好,没有必要告诉它什么时候应该收集未使用的对象。它会自行决定何时应该这样做,而且通常它比你做得更好,因为它可以访问大量关于内存状态和机器状态的信息,而你的代码没有这些信息。

    您可能觉得应该尽量保持较低的内存使用率,但这本身并没有什么好处。计算机不能更好地工作,因为它有更多的可用内存。相反,如果您的代码尝试进行清理,或者强制垃圾收集器进行任何操作,那么它正在忙于做更重要的事情时进行清理。如果需要,垃圾收集器会清理未使用的对象。

    【讨论】:

    • Dispose 方法有一个神奇之处。它会在using 语句中创建的对象上自动调用。
    • @tvanfosson:这仍然没有什么神奇之处,而且是using语句专门针对Dispose方法做了一些事情,Dispose方法仍然只是一个普通的方法。
    • 我意识到该方法在任何实质性方面与其他方法没有区别,但我想说它在退出 using 块时自动调用它有点神奇。
    【解决方案2】:

    这里的其他人已经充分回答了“IDisposable 如何与垃圾收集器交互”和“我什么时候应该调用GC.Collect”部分问题。

    我有一篇博文详细介绍了when you should set variables to null to help the garbage collector(问题的第三部分)。简短的回答是“几乎永远不会,除非它是一个静态变量。”

    【讨论】:

      【解决方案3】:

      对于您的类对象,您正在定义Dispose 将做什么。您实现 IDisposable 接口,该接口包含方法 Dispose 并取决于实现。但通常Dispose 的目的是释放资源(托管/非托管)并使对象成为GC 的候选对象。

      关于设置null,我们可以说是没用的。它只是注意到没有对该对象的引用,因此它成为GC 的候选对象,但同样没有必要设置null,因为GC 可以发现没有该对象就没有引用..

      不建议调用 Collect(除非您对此有极端需要和论据),因为 GC 已优化以知道什么是 Collection 的正确时间。

      【讨论】:

      • “但通常 Dispose 会将对象作为 GC 的候选对象。”...嗯,不。
      • Dispose 不会使对象成为候选对象 - 您可以保留对该对象的引用以阻止它被收集。如果开发人员的工作正确,Dispose 应该清理所有对象内部资源。
      • 另外,在某些对象上,设置 null 是有用的 - 可以在代码中管理具有广泛范围的对象,而不是使用范围来确定其引用计数。设置 null 将使其在超出范围之前就可以进行 GC。
      • @Adan 和@CaptainTom 我并不是说它适合你,我的意思是目的是(释放资源并成为 GC 的候选人)。就像您可以使用称为 Add 的方法并在实现中进行乘法一样,但目的是 Addition。希望它说得清楚。
      • @Adam,实际上,在方法不再使用它时,编译器已经使它有资格在超出范围之前进行 GC。请在此处查看 Jon 的回复:stackoverflow.com/questions/3101530/…
      【解决方案4】:

      当调用 Dispose() 时,该对象仅被标记为垃圾回收。

      来自 MSDN -

      在大多数情况下,垃圾收集器 可以确定执行的最佳时间 一个集合,你应该让它运行 独立。有稀有 强制收集的情况 可能会改善您的应用程序 表现。在这些情况下,您可以 通过使用 强制垃圾收集方法 收藏

      查看这篇文章 - http://msdn.microsoft.com/en-us/library/bb384155.aspx

      【讨论】:

      • 这是不正确的。 Dispose 用作确定性终结的一种形式,但不公开 IDisposable 的对象仍将被 GC 收集。
      • "-1" 您参考了 GC.Collect() 描述。没有什么像“当调用 Dispose() 时,对象仅被标记为垃圾回收”
      • 糟糕.. 好吧,我错了,Dispose() 与垃圾收集没有任何关系。感谢您指出。
      【解决方案5】:

      如果正确实施,Dispose 将释放它拥有的所有实现 IDisposable 的托管资源,并立即释放所有非托管资源。当没有对它的引用时,对象本身将被标记为收集。通常,该对象在using 块中使用,并且在该块的末尾自动调用 Dispose 方法,此时对象超出范围并符合收集条件。

      在一般情况下,您会导致比直接与垃圾收集器交互所解决的问题更多的问题。如果您觉得必须这样做,则更有可能是您需要重构解决方案的信号 - 即,您的类之间的耦合过多,导致对象保持活动的时间超过必要的时间。更简洁的架构可能会导致系统更好地管理对象生命周期。

      有关如何implement the IDisposable pattern 的讨论,请参阅 MSDN。

      【讨论】:

        【解决方案6】:

        如果你真的想强制垃圾收集使用:

        GC.Collect();
        

        请参阅这篇文章,了解您不应该使用它的原因:

        What's so wrong about using GC.Collect()?

        【讨论】:

        • 但是应该你强制垃圾回收吗?在几乎所有情况下:不!
        • -1 你忘了说明你刚才给他的代码不应该被使用,以及为什么。
        • 但是除非你真的确定它会有所帮助,否则不要使用它。例如,文档说:“当在应用程序代码中的定义点使用的内存量显着减少时,请使用 Collect 方法。”。我在一个运行大量工作的“作业”的程序中使用了它,在作业之间或之后进行清理,这确实有助于在程序不做任何事情时减少内存占用。
        • 有些时候你确实不得不使用它。当大量内存密集型操作以非常快的顺序运行时,我不得不使用它。我的循环对于垃圾收集器来说发生得太快了,因此我在 4 个循环后内存不足。在每个循环结束时强制进行垃圾收集可以及时进行清理,因此机器不会耗尽内存。
        【解决方案7】:

        当一个对象没有针对它的引用时,它就有资格进行 GC。如果它在一段时间内(由垃圾收集器管理)有针对它的引用,它开始通过所谓的“世代”得到提升。

        Dispose 方法只是一种模式(不是语言强加的对象删除机制),表示对象现在可以清理任何非托管资源、关闭任何连接等。

        Dispose 方法执行的操作完全由程序员控制,就您所知,它可能什么都不做。

        垃圾收集器对 Dispose 方法不感兴趣 - 但通过终结器,很可能无论如何都会调用对象的 Dispose 逻辑 - 遵循 IDisposable 模式的人将终结器作为最后一道防线“你忘了调用 Dispose 所以我会在 GC 杀死我之前这样做”以清理资源。

        请注意,如果未调用 Dispose,则任何托管资源最终都会被 GC(除非保留引用)。但是,非托管资源仅在您的整个应用程序进程完成时才会被回收(以及仍然持有引用的任何托管资源)。

        【讨论】:

        • 顺便说一句,Dispose 的实现经常包括对GC.SuppressFinalize(this); 的调用,这样当对象被垃圾回收时就不会再次发生终结。
        【解决方案8】:

        自动垃圾回收的意义在于您不必担心释放对象。不要试图“帮助”垃圾收集器。

        对象超出范围后最终会被垃圾回收。没有办法手动“释放”对象或标记它以加快垃圾收集速度。请记住哪些对象在范围内(或从范围内的对象引用)。​​

        Dispose 方法只是一个方法。它与垃圾收集无关。 “Dispose”恰好是using 语句调用的方法的名称:

        using (var x = expr) { ... }
        

        基本上等价于

        var x = expr;
        try { ... } finally { x.Dispose(); }
        

        【讨论】:

          【解决方案9】:

          Dispose 通常是frees unmanaged resources owned by the object。调用Dispose 不会触发垃圾回收;您的对象在不再有任何引用时被收集,就像您从未调用过 Dispose 一样。

          将对象引用设置为null 只会导致该引用不再指向该对象;您通常不需要这样做(例如,您几乎不需要将局部变量设置为 null)。

          您也几乎不需要自己触发垃圾回收。您是否看到一个问题表明您需要每 5 分钟运行一次垃圾回收,而不是在运行时选择运行时?

          【讨论】:

          • 好的。感谢大家。我非常了解 Dispose() 和垃圾收集器。
          猜你喜欢
          • 1970-01-01
          • 2011-01-21
          • 1970-01-01
          • 2011-10-15
          • 1970-01-01
          • 2018-12-30
          • 1970-01-01
          • 1970-01-01
          • 2010-12-13
          相关资源
          最近更新 更多