在Dispose()方法中GC.SuppressFinalize(this)的目的是什么?

时间:2010-06-14 15:38:23

标签: c# .net garbage-collection idisposable suppressfinalize

我有以下代码:

public void Dispose()
{
    if (_instance != null)
    {
        _instance = null;
        // Call GC.SupressFinalize to take this object off the finalization
        // queue and prevent finalization code for this object from
        // executing a second time.
        GC.SuppressFinalize(this);
    }
}

虽然有一条评论解释了与GC相关的电话的目的,但我仍然不明白为什么会这样。

一旦所有实例都停止存在,对象是不是用于垃圾收集的对象,例如,在using块中使用时?

这会起到重要作用的用例场景是什么?

5 个答案:

答案 0 :(得分:33)

在实施配置模式时,您还可以向调用Dispose()的类添加终结器。这是为了确保Dispose() 总是被调用,即使客户忘记调用它。

要防止dispose方法运行两次(如果已经处置了对象),则添加GC.SuppressFinalize(this);。该文档提供了sample

class MyResource : IDisposable
{
    [...]

    // This destructor will run only if the Dispose method 
    // does not get called.
    ~MyResource()      
    {
        // Do not re-create Dispose clean-up code here.
        // Calling Dispose(false) is optimal in terms of
        // readability and maintainability.
        Dispose(false);
    }

    // Implement IDisposable.
    // Do not make this method virtual.
    // A derived class should not be able to override this method.
    public void Dispose()
    {
        Dispose(true);
        // This object will be cleaned up by the Dispose method.
        // Therefore, you should call GC.SupressFinalize to
        // take this object off the finalization queue 
        // and prevent finalization code for this object
        // from executing a second time.
        GC.SuppressFinalize(this);
    }

    private void Dispose(bool disposing)
    {
        // Check to see if Dispose has already been called.
        if(!this.disposed)
        {
            // If disposing equals true, dispose all managed 
            // and unmanaged resources.
            if(disposing)
            {
                // Dispose managed resources.
                component.Dispose();
            }

            // Call the appropriate methods to clean up 
            // unmanaged resources here.
            resource.Cleanup()          
        }
        disposed = true;         
    }
}

答案 1 :(得分:31)

垃圾收集:GC不再引用对象时回收对象使用的内存。

Dispose :IDisposable接口中的一个方法,用于在程序员调用它时(直接或间接通过using块)释放所有托管和非托管资源。

Finalizer :释放所有非托管资源的方法。在回收内存之前由GC调用。

托管资源:任何实现IDisposable接口的.NET类,如Streams和DbConnections。

非托管资源:托管资源类中包含的填充。 Windows句柄是最简单的例子。


现在回答你的问题:

GC保留所有对象的列表(Finalization Queue),其中的类声明了Finalizer(在C#中为~ClassName)。对象在创建时放入此队列中。 GC定期运行以检查程序中是否有任何对象无法访问。然后,它检查是否从Finalization Queue引用了任何不可访问的对象,并将它们放在另一个名为Freacheable队列的队列中,而其余的则被回收。一个单独的线程用于运行Freacheable队列中对象的Finalize方法。

GC下次运行时,会发现之前Freacheable队列中的一些对象已经完成,因此可以进行回收。请注意,GC需要至少两个周期(如果要进行大量的Finalization,则需要更多的周期)来摆脱具有Finalizer的对象,这会导致一些性能损失。

SuppressFinalize方法只是在对象标题中设置一个标志,表示不必运行Finalizer。这样GC就可以立即回收对象的内存。根据上面的定义,Dispose方法与Finalizer(以及更多)执行相同的操作,因此如果执行它,则不再需要Finalization。使用SuppressFinalize方法,您可以通过通知它来保存GC的一些工作。此外,现在您不必在Finalizer中实施检查以避免双重释放。 Dispose唯一的问题是无法保证运行,因为程序员有责任调用它,这就是为什么有时我们需要打扰终结器。


话虽如此,你很少需要编写Finalizer,因为对于绝大多数通常的非托管资源,托管包装器已经存在,并且托管资源将通过调用它们{{1}来释放来自您自己的Dispose方法的方法,仅来自那里!在终结器中,您不能调用Dispose方法。


进一步阅读

答案 2 :(得分:6)

可以在第一次GC运行时完成的对象。

通常,当GC检测到某个对象无法访问时,它会回收它。如果对象可以最终确定,那么GC不会回收它;相反,它认为它仍然可以访问(以及该对象引用的所有对象,等等),并安排它进行最终化。只有在再次再次在完成后的某个时刻无法访问时,才会回收该对象。

这意味着可终结对象会产生额外成本:对象必须在内存中保留较长时间。因此,您看到了这样的呼叫:在不需要时禁止终结是值得的。这里,对象使用finalization来确保它总是在某个时刻被“处理掉”。明确处理时,不再需要最终确定。

答案 3 :(得分:2)

如果你的类型实现了终结器(~MyType() { }),它会阻止垃圾收集器运行它。在终结器处理非托管类型时使用,但用户已经调用Dispose()(显式或通过using() { }块),释放那些非托管类型。

答案 4 :(得分:0)

来自MSDN:GC.SuppressFinalize

  

此方法在对象中设置一个位   标头,系统检查何时   呼叫终结者。 obj参数   必须是这个的来电者   方法

     

实现IDisposable的对象   接口可以调用此方法   IDisposable .. ::。Dispose方法   防止垃圾收集器   调用Object .. ::。Finalize on a   不需要它的对象。

如果你的对象没有引用其他对象,只是离散类型,或者已经将任何对象引用重置为NULL,通常你会使用它。