Finalize 方法和析构函数

对于您的应用程序创建的大多数对象,可以依靠 .NET Framework 的垃圾回收器隐式地执行所有必要的内存管理任务。 但是,在您创建封装非托管资源的对象时,当您在应用程序中使用完这些非托管资源之后,您必须显式地释放它们。 最常见的一类非托管资源就是包装操作系统资源的对象,例如文件、窗口或网络连接。 虽然垃圾回收器可以跟踪封装非托管资源的对象的生存期,但它不了解具体如何清理这些资源。 对于这些类型的对象,.NET Framework 提供 Object.Finalize 方法,它允许对象在垃圾回收器回收该对象使用的内存时适当清理其非托管资源。 默认情况下,Finalize 方法不执行任何操作。 如果您要让垃圾回收器在回收对象的内存之前对对象执行清理操作,您必须在类中重写 Finalize 方法。

注意注意

若要在 C# 中实现 Finalize 方法,您必须使用析构函数语法。在 .NET Framework 2.0 版中,Visual C++ 为实现 Finalize 方法提供了自己的语法,详见Destructors and Finalizers in Visual C++中的介绍。在 .NET Framework 1.0 版和 1.1 版中,Visual C++ 与 C# 一样,也对 Finalize 方法使用析构函数语法。

垃圾回收器使用名为“终止队列”的内部结构跟踪具有 Finalize 方法的对象。 每次您的应用程序创建具有 Finalize 方法的对象时,垃圾回收器都在终止队列中放置一个指向该对象的项。 托管堆中所有需要在垃圾回收器回收其内存之前调用它们的终止代码的对象都在终止队列中含有项。

注意注意

GC.KeepAlive 方法提供的代码示例演示攻击性垃圾回收如何会导致终结器在已回收的对象的成员仍在执行时运行,以及如何使用 KeepAlive 方法来阻止这种情况的发生。

Finalize 方法不应引发异常,因为应用程序无法处理这些异常,而且这些异常会导致应用程序终止。

实现 Finalize 方法或析构函数对性能可能会有负面影响,因此应避免不必要地使用它们。 用 Finalize 方法回收对象使用的内存需要至少两次垃圾回收。 当垃圾回收器执行回收时,它只回收没有终结器的不可访问对象的内存。 这时,它不能回收具有终结器的不可访问对象。 它改为将这些对象的项从终止队列中移除并将它们放置在标为准备终止的对象列表中。 该列表中的项指向托管堆中准备被调用其终止代码的对象。 垃圾回收器为此列表中的对象调用 Finalize 方法,然后,将这些项从列表中移除。 后来的垃圾回收将确定终止的对象确实是垃圾,因为标为准备终止对象的列表中的项不再指向它们。 在后来的垃圾回收中,实际上回收了对象的内存。

请参见

参考

Finalize

概念

重写 Finalize 方法

C# 与 C++ 中的析构函数语法