垃圾回收: GC会在对象不再被引用时回收所使用的内存。
Dispose: IDisposable接口中的一个方法,程序员可以通过直接或间接地使用using块调用该方法来释放所有托管和非托管资源。
Finalizer: 一个方法用于释放所有非托管资源。在回收内存之前,GC会调用这个方法。
托管资源: 实现IDisposable接口的任何.NET类,如Streams和DbConnections。
非托管资源: 包装在托管资源类中的东西。Windows句柄是最简单的例子。
现在来回答您的问题:
GC维护了一个列表(Finalization Queue),其中包含了所有类声明了Finalizer(~ClassName在C#中)的对象。创建对象时,将其放入此队列中。GC定期运行以检查程序中是否有任何无法访问的对象。然后它会检查是否有不可访问对象从Finalization Queue中引用,将这些对象放入另一个称为“可达队列”的队列中,而其余对象则被丢弃。使用单独的线程运行Freacheable队列中对象的Finalize方法。
下次GC运行时,它会发现一些先前在可达队列中的对象已经被Finalized,因此可以准备回收。请注意,GC需要至少两个周期(或更多,如果有很多Finalization需要执行)来消除具有Finalizer的对象,这会产生一些性能损失。
SuppressFinalize
方法仅在对象头中设置一个标志,表示不必运行终结器。这样,GC就可以立即回收对象的内存。根据上述定义,
Dispose
方法与终结器执行相同的操作(以及更多),因此如果执行了该方法,则不再需要终结器。使用
SuppressFinalize
方法,您可以通过通知GC来保存一些工作。此外,现在您不必在终结器中实现检查以避免重复释放。唯一的问题是
Dispose
不保证运行,因为调用它是程序员的责任,这就是为什么有时我们需要使用终结器的原因。
话虽如此,你很少需要编写终结器,因为对于绝大多数常规的非托管资源,都已经存在托管包装器,并且托管资源必须通过从自己的
Dispose
方法和仅从那里调用它们的
Dispose
方法来释放!在终结器中,您决不能调用Dispose方法。
进一步阅读:
Dispose()
总是被调用的方法吗?如果不能确定Dispose
总是被调用,那么未托管的内存或其他本机资源将如何清理? - Dirk VollmarSafeHandle
几乎总是不需要使用终结器,因为它可以自动进行处理(以各种方式)来完成句柄的终止。 - Jon SkeetGC.SuppressFinalize
的成本与调用GC.KeepAlive
的成本相差无几,如果将其中任何一个放在最后,都将确保在“Dispose”完成之后内部对象不再具有终结资格。 - supercat