9

假设这是传统的 Dispose 模式(取自 devx,但在许多网站上都可以看到)

class Test : IDisposable
{
  private bool isDisposed = false;

  ~Test()
  {
    Dispose(false);
  }

  protected void Dispose(bool disposing)
  {
    if (disposing)
    {
      // Code to dispose the managed resources of the class
    }

    // Code to dispose the un-managed resources of the class

    isDisposed = true;
  }

  public void Dispose()
  {
    Dispose(true);
    GC.SuppressFinalize(this);
  }
}

我不明白我们为什么要打电话GC.SupressFinalize(this)。这需要我编写自己的托管资源处置,包括将我的引用归零?我有点失落,我必须承认。有人可以阐明这种模式吗?

理想情况下,我只想处理我的非托管资源,让 GC 自己进行托管收集。

实际上,我什至不知道我们为什么要指定终结器。无论如何,编码人员应该自己调用 dispose ,不是吗?如果这只是一个后备机制,我会删除它。

4

6 回答 6

16

使用该模式以便对象可以在客户端代码调用IDisposable该方法时确定性地清理其资源。Dispose

终结器仅作为备用,以防客户端代码Dispose由于某种原因无法调用。

如果客户端代码调用Dispose,那么资源的清理会在那里执行,并且在最终确定期间不需要再次完成。在这种情况下调用SuppressFinalize意味着对象不再产生额外的最终确定 GC 成本。

而且,如果你自己的类只使用托管资源,那么终结器是完全没有必要的:GC 将处理任何托管资源,让这些资源自己担心它们是否需要后备终结器。如果它直接处理非托管资源,您应该只考虑在您自己的类中使用终结器。

于 2010-12-19T23:53:39.047 回答
4

SuppressFinalize抑制任何自定义终结器。

它不会改变任何其他 GC 行为。
永远不需要显式地清空引用。(除非您希望他们尽早收集)

没有任何终结器的类和您调用的实例之间没有区别SuppressFinalize

调用SuppressFinalize可以防止对 的额外调用Dispose(false),并使 GC 更快一些。(终结器很昂贵)

请注意,没有非托管资源的类不应该有终结器。(它们仍然应该调用SuppressFinalize,除非它们被密封;这允许继承的类添加非托管资源)

于 2010-12-19T23:56:13.587 回答
2

SuppressFinalize 调用存在于某些派生类决定添加终结器的情况下。如果正常处置成功完成,则不需要完成;即使派生类决定添加一个,SuppressFinalize 调用也会阻止它执行和干扰垃圾收集。

要理解为什么这很重要,您应该认为终结不是垃圾收集的一部分,而是在它之前发生的事情。当一个类注册完成时(在创建时自动,如果它覆盖 Finalize),它会被放入一个名为 Finalization Queue 的特殊列表中。 终结队列中的任何对象,以及队列中的对象直接或间接引用的任何对象,都不能被垃圾回收,但如果发现终结队列中的任何对象除了来自队列之外没有根引用,对象将从队列中拉出并运行终结器。在派发终结器时,该对象将不可回收(因为在派发期间将存在引用);一旦终结器完成,通常不会再有对该对象的任何引用,因此它(以及由此引用的对象)通常是可收集的。

就个人而言,我认为 SuppressFinalize 是愚蠢的,因为我想不出派生类应该有终结器的充分理由。如果派生类要添加父类一无所知的非托管资源(*),则应创建另一个类来保存这些资源;父类应该持有对它的引用。这样,父类本身就不需要终结,并且父类引用的对象不会被不必要地阻止垃圾收集。

于 2010-12-20T01:26:04.680 回答
2

来自Msdn: “该方法在对象头中设置了一些位,系统在调用终结器时会检查该位。obj参数必须是该方法的调用者。实现IDisposable接口的对象可以从IDisposable.Dispose调用该方法防止垃圾收集器在不需要它的对象上调用 Object.Finalize 的方法。”

因此它可以防止来自 GC 的额外调用。如果在终结器方法中调用它,当对象被终结时,它不会做任何事情,因为它已经被终结了。否则,允许 GC 回收内存,而无需最终确定对象,从而使事情变得更快。

于 2012-04-03T16:45:09.460 回答
1

正如MSDN上所述,执行 Finalize 方法的成本很高。通过调用 dispose 你已经自我终结了你的类,所以不需要调用终结器。如果您的代码(或“拥有”实例的任何人)从未直接调用 Dispose,则实现终结器。

于 2010-12-19T23:59:03.357 回答
0
// If the monitor.Dispose method is not called, the example displays the following output:
//       ConsoleMonitor instance....
//       The ConsoleMonitor class constructor.
//       The Write method.
//       The ConsoleMonitor finalizer.
//       The Dispose(False) method.
//       Disposing of unmanaged resources.
//       
// If the monitor.Dispose method is called, the example displays the following output:
//       ConsoleMonitor instance....
//       The ConsoleMonitor class constructor.
//       The Write method.
//       The Dispose method.
//       The Dispose(True) method.
//       Disposing of managed resources.
//       Disposing of unmanaged resources.

来自https://msdn.microsoft.com/en-us/library/system.gc.suppressfinalize(v=vs.110).aspx

于 2018-02-28T12:41:30.190 回答