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

mr.*_*r.b 29 .net c# 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);
    }
}
Run Code Online (Sandbox Code Playgroud)

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

一旦所有实例都停止存在,就不会将对象注定为垃圾收集,例如,当在using块中使用时?

什么是用例场景,它将发挥重要作用?

Dir*_*mar 34

在实现dispose模式时,您还可以向调用的类添加终结器Dispose().这是为了确保Dispose() 始终被调用,即使客户端忘记调用它.

要防止dispose方法运行两次(如果已经放置了对象),则添加GC.SuppressFinalize(this);.文档提供了一个示例:

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;         
    }
}
Run Code Online (Sandbox Code Playgroud)

  • 你*可能*添加终结器.但根据我的经验,很少.有很多时候在没有终结器的情况下实现IDisposable是有意义的. (13认同)
  • @ mr.b:如果*直接*拥有非托管资源,您只需要一个终结器.如果您刚刚参考了IDisposable的其他实现,则不需要终结器.`SafeHandle`几乎总是不需要终结器,因为它为句柄添加了自动终结(各种风格). (11认同)

kic*_*sit 32

垃圾收集: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,因为对于绝大多数通常的非托管资源,托管包装器已经存在,并且通过Dispose从你自己的Dispose方法调用方法来释放托管资源,从那里来!在终结器中,您必须永远不要调用Dispose方法.


进一步阅读:


Tho*_*nin 6

在第一次GC运行后,可以完成的对象可以使用.

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

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

  • @Aaronaught:本文的"Finalization Internals"部分是一个很好的概述:http://msdn.microsoft.com/en-us/magazine/bb985010.aspx (2认同)