339

在 .NET 中,我应该在什么情况下使用GC.SuppressFinalize()?

使用这种方法能给我带来什么好处?

4

5 回答 5

343

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
于 2008-09-29T23:56:03.623 回答
43

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

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

一般来说,大多数任何Dispose()方法都应该能够调用GC.SupressFinalize(),因为它应该清理所有将在终结器中清理的内容。

SupressFinalize只是提供了一种优化,使系统不必费心将对象排队到终结器线程。正确编写的Dispose()/finalizer 在调用或不调用GC.SupressFinalize().

于 2008-09-29T22:44:21.593 回答
3
Dispose(true);
GC.SuppressFinalize(this);

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

由于我们有 call Dispose(true),它清除对象,所以我们不需要完成队列来完成这项工作。

所以在完成队列中调用GC.SuppressFinalize(this)删除引用。

于 2018-04-16T01:54:03.387 回答
1

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

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

于 2018-04-26T23:05:22.277 回答
0

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

请参阅:GC.SuppressFinalize(Object) 方法 - Microsoft Docs

于 2008-09-29T22:44:11.703 回答