我什么时候应该使用GC.SuppressFinalize()?

时间:2008-09-29 22:41:40

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

在.NET中,我应该在哪种情况下使用GC.SuppressFinalize()

使用这种方法有什么好处可以给我?

5 个答案:

答案 0 :(得分:277)

SuppressFinalize只能由具有终结器的类调用。它通知垃圾收集器(GC)this对象已被完全清理。

有终结器时推荐的IDisposable模式是:

public class MyClass : IDisposable
{
    private bool disposed = false;

    protected virtual void Dispose(bool disposing)
    {
        if (!disposed)
        {
            if (disposing)
            {
                // called via myClass.Dispose(). 
                // OK to use any private object references
            }
            // Release unmanaged resources.
            // Set large fields to null.                
            disposed = true;
        }
    }

    public void Dispose() // Implement IDisposable
    {
        Dispose(true);
        GC.SuppressFinalize(this);
    }

    ~MyClass() // the finalizer
    {
        Dispose(false);
    }
}

通常,CLR在创建对象时会使用终结器对对象进行标记(使创建起来更加昂贵)。 SuppressFinalize告诉GC该对象已正确清理,无需进入终结器队列。它看起来像一个C ++析构函数,但不会像一个人那样行事。

SuppressFinalize优化并不简单,因为您的对象可以在终结器队列上等待很长时间。不要试图在其他物体上调用SuppressFinalize。这是一个等待发生的严重缺陷。

设计指南告诉我们,如果您的对象实现了IDisposable,则不需要终结器,但是如果您有终结器,则应该实现IDisposable以允许确定性地清理您的类。

大多数情况下,您应该能够使用IDisposable来清理资源。当对象保留在非托管资源上并且需要保证清理这些资源时,您应该只需要一个终结器。

注意:有时编码器会添加一个终结器来调试自己的IDisposable类的构建,以便测试代码是否正确处理了它们的IDisposable对象。

    public void Dispose() // Implement IDisposable
    {
        Dispose(true);
    #if DEBUG
        GC.SuppressFinalize(this);
    #endif
    }

    #if DEBUG
    ~MyClass() // the finalizer
    {
        Dispose(false);
    }
    #endif

答案 1 :(得分:35)

你告诉系统,在终结器中完成的任何工作都已完成,因此不需要调用终结器。来自.NET文档:

  

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

通常,大多数Dispose()方法都应该能够调用GC.SupressFinalize(),因为它应该清理在终结器中清理的所有内容。

SupressFinalize只是提供一种优化,允许系统不打扰将对象排队到终结器线程。无论是否调用GC.SupressFinalize(),正确编写的Dispose()/ finalizer都可以正常工作。

答案 2 :(得分:2)

必须在实现IDisposable的对象的Dispose方法上调用该方法,这样如果有人调用Dispose方法,GC就不会再次调用终结器。

请参阅:http://msdn.microsoft.com/en-us/library/system.gc.suppressfinalize.aspx

答案 3 :(得分:1)

 Dispose(true);
 GC.SuppressFinalize(this);

如果对象有终结器,.net会在终结队列中放置一个引用

由于我们已经调用了Dispose(ture),它清除了对象,因此我们不需要最终化队列来完成这项工作。

所以调用GC.SuppressFinalize(this)删除finalization队列中的引用。

答案 4 :(得分:0)

如果一个类或从它派生的任何东西可能持有对具有终结器的对象的最后一个实时引用,那么在任何可能的操作之后应该在该对象上调用GC.SuppressFinalize(this)GC.KeepAlive(this)受到终结器的不利影响,从而确保终结器在该操作完成后才能运行。

GC.KeepAlive()GC.SuppressFinalize(this)的费用在没有终结器的任何类中基本相同,而且具有终结器的类通常应调用GC.SuppressFinalize(this),因此使用后一个函数作为Dispose()的最后一步可能并不总是必要的,但它不会是错误的。