关于c#:何时应使用GC.SuppressFinalize()?

When should I use GC.SuppressFinalize()?

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

使用此方法有什么优点?


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

拥有终结器的建议IDisposable模式为:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
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对象。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
    public void Dispose() // Implement IDisposable
    {
        Dispose(true);
    #if DEBUG
        GC.SuppressFinalize(this);
    #endif
    }

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


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

Objects that implement the IDisposable
interface can call this method from
the IDisposable.Dispose method to
prevent the garbage collector from
calling Object.Finalize on an
object that does not require it.

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

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


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

如果对象具有终结器,.net会将引用放入终结队列中

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

因此,调用GC.SuppressFinalize(this)在完成队列中删除引用。


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

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


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

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