首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >Dispose()方法中的GC.SuppressFinalize(this)的用途是什么?

Dispose()方法中的GC.SuppressFinalize(this)的用途是什么?
EN

Stack Overflow用户
提问于 2010-06-14 23:38:23
回答 5查看 25K关注 0票数 32

我有以下代码:

代码语言:javascript
复制
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块中使用时?

这将发挥重要作用的用例场景是什么?

EN

回答 5

Stack Overflow用户

回答已采纳

发布于 2010-06-14 23:42:43

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

为了防止dispose方法运行两次(如果对象已经被释放),需要添加GC.SuppressFinalize(this);。该文档提供了一个sample

代码语言:javascript
复制
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;         
    }
}
票数 35
EN

Stack Overflow用户

发布于 2010-06-15 00:30:05

垃圾收集:当对象不再被引用时,GC将回收该对象所使用的内存。

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

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

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

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

现在回答你的问题:

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

下次GC运行时,它会发现之前在Freacheable队列中的一些对象已经完成,因此准备回收。请注意,GC至少需要两个周期(如果有很多终结器要做,则需要更多的周期)才能使用终结器来清除对象,这会导致一些性能损失。

SuppressFinalize方法只是在object头中设置一个标志,该标志指示终结器不必运行。这样,GC就可以立即回收对象的内存。根据上面的定义,Dispose方法与Finalizer做同样的事情(甚至更多),所以如果它被执行了,那么Finalization就不再是必要的了。使用SuppressFinalize方法,您可以通知GC这一事实,从而为GC节省一些工作。此外,现在您不必在终结器中实现检查,以避免双重释放。Dispose的唯一问题是不能保证运行,因为调用它是程序员的责任,这就是为什么有时我们需要麻烦终结器的原因。

也就是说,您很少需要编写终结器,因为对于大多数常见的非托管资源,托管包装器已经存在,并且托管资源将通过从您自己的Dispose方法调用它们的Dispose方法来释放,并且只能从那里!在终结器中,决不能调用Dispose方法。

进一步阅读

  • Dispose, Finalization, and Resource Management
  • http://www.codeproject.com/KB/dotnet/idisposable.aspx
票数 34
EN

Stack Overflow用户

发布于 2010-06-14 23:46:12

可以最终确定的对象在第一次GC运行后仍然存在。

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

这意味着可finalizable对象会产生额外的成本:该对象必须在内存中保留更长时间。因此,你会看到这样的调用:在不需要的时候取消finalization是值得的。在这里,对象使用finalization来确保它总是在某个时刻被“处理”。当它被显式处理时,它不再需要被最终确定。

票数 6
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/3038571

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档