19

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

(搜索没有显示好的答案,所以我添加了这个问题,希望与不太容易发现的实际答案合并。除此之外,我已经知道答案并将添加几天后它以防万一没有人提到它。)

4

2 回答 2

24

正如Raymond Chen 解释的那样,终结器实际上可能永远不会被执行。这个问题是在他一年一度的 CLR 周期间被问到的,这有点有趣,就在他解释它的两天后 :)

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

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

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

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

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

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


终结器可能不会运行,例如,如果:

  • 另一个终结器抛出异常。
  • 另一个终结器需要 2 秒以上。
  • 所有终结器加起来需要 40 多秒。
  • AppDomain 崩溃或被卸载(尽管您可以使用关键终结器(CriticalFinalizerObject、SafeHandle 或类似的东西)规避这个问题)
  • 没有垃圾收集发生
  • 进程崩溃

(注意:时间值可能会随着时间的推移而改变,但前段时间肯定是正确的。)

我想还有很多事情会导致终结器永远不会运行。底线是,除了来自陈先生的引用之外,终结器是一个安全网,可以减少错误的影响,因为例如资源有时会被释放,如果你忘记明确地这样做,这总比没有好。

于 2010-08-11T12:30:07.073 回答
6

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

如果你调用SuppressFinalizer对象,你也可以抑制终结器。

来自MSDN (Object.Finalize):

在以下异常情况下,Finalize 方法可能不会运行完成或根本不会运行:

  • 另一个终结器无限期地阻塞(进入一个无限循环,试图获得一个它永远无法获得的锁,等等)。因为运行时会尝试运行终结器以完成,所以如果终结器无限期地阻塞,则可能不会调用其他终结器。
  • 该进程在没有给运行时清理机会的情况下终止。在这种情况下,运行时的第一个进程终止通知是 DLL_PROCESS_DETACH 通知。
于 2010-08-11T12:27:52.447 回答