.net终结器总是被执行吗?

时间:2010-08-11 12:26:50

标签: .net garbage-collection finalizer

终结器是否可以保证在某些时候在.NET中执行(备用电源中断等)?我知道GC是如何工作的,并且当它们完全运行时它是不确定的。

(搜索没有显示出好的答案,所以我加入了这个问题,期望与不那么容易发现的实际答案合并。除此之外,我已经知道了如果没有人提及它,我会回答并在几天之后添加它。)

2 个答案:

答案 0 :(得分:24)

终结者实际上可能从未执行,Raymond Chen explains。有趣的是,这个问题在他的年度CLR周期间被问到,就在他解释它的两天后:)

对于懒惰的人来说,(或者更确切地说,一个)结论是:

  

正确编写的程序不能假定终结器将会运行。

如果您想知道是否可以依赖终结器,这已经是您必须知道的一切:不要依赖终结器。

正如Raymond Chen在链接文章中所述:

  

终结者是一个安全网,而不是资源回收的主要手段。

如果您正在寻找如何释放资源,请查看一次性模式。


终结器可能无法运行,例如,如果:

  • 另一个终结者抛出异常。
  • 另一个终结者需要超过2秒钟。
  • 所有终结者共同花费超过40秒。
  • AppDomain崩溃或被卸载(尽管您可以使用关键终结器(CriticalFinalizerObject,SafeHandle或类似的东西)绕过它)
  • 不会发生垃圾收集
  • 进程崩溃

(注意:时间值可能随时间变化but were certainly true some time ago。)

我想还有很多东西会导致终结者永远不会跑。除了陈先生的引言之外,底线是终结者是一个安全网,可以减少错误的影响,因为例如资源有时被释放, 永远不会,如果你忘了明白这一点。

答案 1 :(得分:6)

如果终结器抛出异常,则其他终结器将不会执行。

如果您在对象上调用SuppressFinalizer,也可以取消终结器。

来自MSDN(Object.Finalize):

  

在以下特殊情况下,Finalize方法可能无法完成或根本无法运行:

     
      
  • 另一个终结器无限期地阻塞(进入无限循环,尝试获得它永远无法获得的锁等等)。因为运行时尝试将终结器运行完成,所以如果终结器无限期地阻塞,则可能不会调用其他终结器。
  •   
  • 该过程终止,而不给运行时提供清理的机会。在这种情况下,运行时的第一个进程终止通知是DLL_PROCESS_DETACH通知。
  •