咨询区
-
GEOCHET
在 .NET 中,请问哪一种情况必须要使用 GC.SuppressFinalize()
方法,它到底能给到我什么好处?.
回答区
-
Robert Paulson
SuppressFinalize()
方法只能被含有终结器方法的类使用,它通知 GC 这个 this
对象已经被手工清理了。
建议在 含有 finalizer
方法的类上使用 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);
}
}
通常来说,如果一个含有 finalizer
方法的类被创建,那么 CLR 就会一直密切监控着它,所以它的创建相比普通的类要更加昂贵一些,而 SuppressFinalize
方法就是告诉GC,我已经清除完毕了,你不需要从 FinalizeQueue
中去提取,这就有点像 C++ 的析构函数,但本质上不是一个东西。
点评区
其实很好理解,当创建了一个带有 finalizer
方法的类,那这个类的实例地址也会在 FinalizeQueue
中存放一份,当 GC 回收该对象时,GC会将其放到 FreachableQueue
队列中,这样终结器线程就能够从这个队列中提取,进而执行对象的 finalizer
方法,可以参考下面的代码:
namespace ConsoleApp5
{
class Program
{
static void Main(string[] args)
{
Run();
GC.Collect();
Console.ReadLine();
}
static void Run()
{
var person = new Person();
Console.WriteLine("person 已实例化!");
}
}
class Person
{
~Person()
{
Console.WriteLine("我是析构函数!");
Console.ReadLine();
}
}
}
接下来问题来了,我能不能不要让 终结器线程
来执行我的析构函数呢?这就需要用 SuppressFinalize()
方法来抑制了,修改 Run
方法如下:
static void Run()
{
var person = new Person();
Console.WriteLine("person 已实例化!");
GC.SuppressFinalize(person);
}
可以看到,这回 终结器线程
没有执行我的析构函数
了,就这么简单,如果有朋友对细节感兴趣,有机会用 windbg 让大家眼见为实。