2010-04-09 58 views
19

我有几个问题,我无法得到正确的答案。我们为什么要在没有析构函数时调用SuppressFinalize

1)为什么当我们没有析构函数时,我们应该在Dispose函数中调用SuppressFinalize。

2)Dispose和finalize用于在垃圾收集对象之前释放资源。无论是托管资源还是非托管资源,我们需要释放资源,那么为什么我们需要在dispose函数内部存在一个条件,当我们从IDisposable调用这个重写函数时传递'true':Dispose并在从finalize调用时传递false。

看到下面的代码,我从网上复制。

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); 
    } 
    } 

如果我删除了布尔保护的Dispose函数并执行如下操作,该怎么办?

class Test : IDisposable 
    { 
    private bool isDisposed = false; 

    ~Test() 
    { 
     Dispose(); 
    } 


    public void Dispose() 
    { 
     // Code to dispose the managed resources of the class 
     // Code to dispose the un-managed resources of the class 
     isDisposed = true; 

     // Call this since we have a destructor . what if , if we don't have one 
     GC.SuppressFinalize(this); 
    } 
    }  

回答

17

我在这里出门,但是...大多数人不需要需要全面的配置模式。它被设计成在直接访问非托管资源(通常通过IntPtr)和面对继承时是坚实的。大多数时候,这些都不是必需的。

如果你只是持有一个实现IDisposable的其他东西的引用,那么你几乎肯定不需要终结器 - 无论是直接保存资源都负责处理这个事件。你可以做这样的事情:

public sealed class Foo : IDisposable 
{ 
    private bool disposed; 
    private FileStream stream; 

    // Other code 

    public void Dispose() 
    { 
     if (disposed) 
     { 
      return; 
     } 
     stream.Dispose(); 
     disposed = true; 
    } 
} 

注意,这不是线程安全的,但是这可能不会是一个问题。由于不必担心子类直接持有资源的可能性,因此不需要禁止终结器(因为没有一个) - 而且您不需要提供一种子类的方法来定制处置。没有继承,生活更简单。

如果你需要允许不受控制的继承(即你不愿意打赌子类将有非常特殊的需求),那么你需要去完整的模式。

请注意,与.NET 2.0中的SafeHandle相比,在.NET 1.1中需要自己的终结器更为罕见。


为了解决您为什么有一个在首位disposing标志点:如果你是一个终结之内运行,你指的可能已经敲定的其他对象。你应该让他们自己清理一下,你应该只清理你自己的资源,直接

+0

嗨,乔恩,只是挑剔,但句子“任何持有资源直接可以处理的”,应该可能是“将处理该”,(即“可以” - >“将”),以强调根本不是外部班级的工作。 – 2010-04-09 10:21:13

+0

还有一个问题,因为System.Object是所有对象的基础,默认情况下它已经实现了一个finalize方法,即使我们没有提供析构函数,也不会将GC放到finalize队列中吗?或者为什么我们说如果我们不提供destrutor对象不会被放入最终队列?因为通过继承保护成员就像派生类的私有成员。 – somaraj 2010-04-09 10:58:46

+0

从非平凡的父类派生的子类是否有任何合法的原因,如果父类不具有清理终结器?我想不出任何情况下,派生类将任何非托管资源封装到自己的类中,并将其自己的终结器完全脱离主类。实际上,即使所有人都想要一个“警钟”终结器,最好将* *封装到它自己的类中,而不是为派生类添加终结器。 – supercat 2012-04-12 15:01:37

5

保留第一个版本,它更安全,并且是正确的dispose模式实现。

  1. 调用SuppressFinalize告诉你已完成所有销毁/处置自己(通过你的类持有的资源),它不需要调用析构函数的GC。

  2. 你需要测试的情况下,使用您的类的代码有已经调用了处置,你不应该告诉GC重新配置。

请参阅this MSDN文档(Dispose方法应该调用SuppressFinalize)。

+0

是我不明白的是SupressFinalze将阻止GC调用敲定。但是我的疑问是,当我没有一个决定者时,为什么我们需要打电话给SupressFinalze。因为Finalize会在终结者队列中调用那些objets,并且我的对象没有析构函数,所以GC不会调用。 2)我的第二个特点是,为什么处理模式坚持要使用布尔值的重载处理函数。这将控制托管或非托管资源的发布。 当对象要处理时,为什么我们需要分别处理资源,让所有的空闲。 – somaraj 2010-04-09 06:36:06

+2

该规则仅在您需要终结器或您需要允许子类具有终结器时才相关。在很多情况下情况并非如此。 – 2010-04-09 06:36:31

+5

@somaraj:问题在于*你的类可能没有终结器,而是一个*子类*。 – 2010-04-09 06:37:09

3

以下是主要事实

1)Object.Finalize是当它有什么类重写终结。 2)如果你在处理Finalization之前在你的Dispose方法中处理资源(例如,当从一个using块中出来时),你可以调用GC.SuppressFinalize等等)。如果你没有Finalizer,那么你不需要这样做。如果你有一个Finalizer,这可以确保该对象从Finalization队列中取出(所以我们不会处理东西两次,因为Finalizer通常也会调用Dispose方法)

3)您将Finalizer实现为'失败安全“机制。终结器保证运行(只要CLR没有中止),所以它们允许你确保代码在Dispose方法未被调用的情况下得到清理(可能程序员忘记在'using'中创建实例,块等

4)终结器是昂贵的,因为类型的终结器无法在第0代收集(最有效)垃圾收集,并提升到第1代与参考他们的F可达性队列,以便它们代表GC根。直到GC执行一个第一代集合,终结器被调用,并且资源被释放 - 所以只有在非常重要的时候才实现终结器 - 并且确保需要最终化的对象尽可能小 - 因为所有可以通过您的可终结对象将达到将被提升到第一代也。

2

1回答第一个问题

基本上,你不必调用SuppressFinalize方法,如果你的类没有一个finalize方法(析构函数)。我相信人们称之为SupressFinalize,即使因缺乏知识而没有最终确定方法。

2回答第二个问题的定案方法的

目的是释放非托管资源。要理解的最重要的事情是,当对象处于最终化队列中时,会调用Finalize方法。垃圾收集器收集所有可能被破坏的物体。垃圾收集器在销毁之前将已完成定稿的对象添加到定型队列中。还有另外一个.net后台进程为那些在最终化队列中的对象调用finalize方法。到后台进程执行finalize方法时,该特定对象的其他托管引用可能已被销毁。因为在最终执行时没有特定的顺序。因此,Dispose模式希望确保finalize方法不会尝试访问托管对象。这就是为什么托管对象在“final(处置)”子句中无法访问finalize方法的原因。

1

您应该始终调用SuppressFinalize(),因为您可能有(或将来有)实现Finalizer的派生类 - 在这种情况下,您需要它。

假设您有一个没有Finalizer的基类 - 并且您决定不调用SuppressFinalize()。然后在3个月后添加一个派生类,添加一个Finalizer。很可能您会忘记进入基类并添加对SuppressFinalize()的调用。如果没有终结器,调用它也没有什么坏处。

我建议IDisposable模式被张贴在这里:How to properly implement the Dispose Pattern

相关问题