2010-08-11 113 views
16

终结器是否保证在某些时候在.NET中执行(备用停电等)?我知道GC是如何工作的,而且它确切的运行时它是不确定的。.net终结器是否始终执行?

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

回答

24

终结,实际上可能是从未执行,为Raymond Chen explains。很有趣,在他的年度CLR周这个问题是问,仅仅两天后,他解释吧:)

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

一个正确写程序不能假定终结器将永远运行。

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

由于雷蒙德陈还指出链接的文章:

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

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


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

  • 另一终结抛出异常。
  • 另一个终结器需要2秒以上。
  • 所有终结者在一起需要超过40秒。
  • 一个AppDomain崩溃或卸载(虽然你可以用批判的终结(CriticalFinalizerObject,SafeHandle的或类似的东西)绕过这个
  • 没有垃圾回收时
  • 的进程崩溃

(注:时间值可能会随着时间而改变,but were certainly true some time ago

我猜还有很多事情可能导致终结者永远不会运行,除了陈先生的引用,底线是,终结符是一个安全网在减少错误的影响,因为例如资源被释放某时,这比好,从来没有,如果你忘记做它的明确性。

+0

你能引用更多的重要部分?是的,也许提问者期待着这个链接。 ;) – mafu 2010-08-11 12:33:26

+0

实际上,由于很多人问他们如何依赖终结者的行为,我认为我*引用了最重要的部分;)另一方面,文章中的其他框也可能很有趣。 – OregonGhost 2010-08-11 12:39:36

+0

@OregonGhost:我是否理解这个权利:如果20个终结器每个都需要1.95秒,那就是笨拙的命令,所有的都会执行 - 需要39秒。如果花费2.05秒,则跳过所有其他执行。这似乎相当破碎。相当粗暴地中断一个需要2秒钟以上的终结器,才能让其他人在40秒超时的剩余时间内运行,这将是一个很好的特性。但是在两秒钟后捣毁事物似乎是一种错误。 – supercat 2010-08-23 20:25:49

6

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

如果您在对象上调用SuppressFinalizer,还可以禁止终结器。

MSDN(Object.Finalize):

finalize方法可能无法完成运行,或可能无法在下列特殊情况下,在所有运行:

  • 另一个终结块无限期(去进入一个无限循环,试图获得它永远不能获得的锁等等)。由于运行时尝试运行终结器以完成,因此如果终结器无限期地阻塞,可能不会调用其他终结器。
  • 该过程终止而没有给运行时间清理的机会。在这种情况下,运行时的第一个进程终止通知是DLL_PROCESS_DETACH通知。
+0

您可以添加“异常”部分的来源吗? – mafu 2010-08-11 12:35:43

+0

请注意,“进入无限循环”在CLR实现中的意思是“需要两秒以上”,如下所述:http://nitoprograms.blogspot.com/2009/08/finalizers-at-process- exit.html – OregonGhost 2010-08-11 12:37:27

+0

@mafutrct - 见这里:http://stackoverflow.com/questions/1538630/exceptions-during-finalize-what-methodology-are-you-using-to-detect-garbage-co – Oded 2010-08-11 12:50:34

相关问题