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

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

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

141349 次浏览

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

看:GC.SuppressFinalize(对象)方法- Microsoft Docs

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

实现IDisposable的对象 接口可以调用此方法 IDisposable。处理方法为 防止垃圾回收 调用对象。最后确定

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

SupressFinalize只是提供了一个优化,允许系统不麻烦将对象排队到结束器线程。正确编写的Dispose()/终结器应该在调用或不调用GC.SupressFinalize()的情况下正常工作。

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
Dispose(true);
GC.SuppressFinalize(this);

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

因为我们已经调用Dispose(true),它清除对象,所以我们不需要结束队列来做这项工作。

因此调用GC.SuppressFinalize(this)删除终结队列中的引用。

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

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