为什么传统的Dispose模式抑制最终化?

时间:2010-12-19 23:51:31

标签: c# dispose finalize

假设这是传统的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自己进行托管收集。

实际上,我甚至不知道为什么要指定终结器。在任何情况下,编码人员都应该自己处理,现在不应该他?如果这只是一个后备机制,我会删除它。

6 个答案:

答案 0 :(得分:14)

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

如果客户端代码由于某种原因无法调用Dispose,则终结者只会作为后备。

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

而且,如果您自己的班级仅使用托管的资源,则完全没必要使用终结者:GC将负责任何托管资源,让这些资源自己担心是否他们需要一个后备终结者。如果直接处理非托管资源,您应该只考虑自己类中的终结者。

答案 1 :(得分:3)

SuppressFinalize 禁止任何自定义终结器。

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

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

调用SuppressFinalize会阻止对Dispose(false)的额外调用,并使GC更快一些。 (终结者很贵)

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

答案 2 :(得分:2)

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

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

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

答案 3 :(得分:2)

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

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

答案 4 :(得分:1)

MSDN所述,执行Finalize方法代价高昂。通过调用dispose,你已经自己完成了你的课程,因此不需要调用终结器。如果您的代码永远不会直接调用Dispose(或者拥有'实例的任何人),则实现终结器。

答案 5 :(得分: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