是不是保证完成运行的析构函数?

析构函数很奇怪 。 我试图通过使用“智能”参考管理来消除使用一次性模式的需要,确保垃圾收集器可以在正确的时间收集对象。 在我的一个析构函数中,我不得不等待来自另一个对象的事件,我注意到它没有。 应用程序只是关闭,析构函数在执行过程中终止。 我希望总是允许析构函数完成运行,但是下面的测试表明这不是真的。

using System; using System.Diagnostics; using System.Threading; namespace DestructorTest { class Program { static void Main( string[] args ) { new DestructorTest(); new LoopDestructorTest(); using ( new DisposableTest() ) { } } } class DestructorTest { ~DestructorTest() { // This isn't allowed to finish. Thread.Sleep( 10000 ); } } class LoopDestructorTest { ~LoopDestructorTest() { int cur = 0; for ( int i = 0; i < int.MaxValue; ++i ) { cur = i; } // This isn't allowed to finish. Debug.WriteLine( cur ); } } class DisposableTest : IDisposable { public void Dispose() { // This of course, is allowed to finish. Thread.Sleep( 10000 ); } } } 

那么, 是不是保证完成运行的析构函数?

那么,是不是保证完成运行的析构函数?

不。从我记忆中,当进程终止时,它会给终结器执行几秒钟,但然后突然终止进程。 你不会想要一个糟糕的终结器来阻止一个进程完成,是吗?

您应该将最终确定视为“尽力而为”的清理 – 特别是,在整个系统突然关闭的情况下,例如BSOD或断电,情况不会发生。

编辑:我从Joe Duffy的博客文章中找到了一些伪文档:

如果在停止所有正在运行的线程的过程中锁被孤立,则关闭代码路径将无法获取锁。 如果这些采集是在非超时(或长时间超时)获取的情况下完成的,则会发生挂起。 为了应对这种情况(以及可能发生的任何其他类型的挂起),CLR会对监视程序线程进行委托,以便密切关注终结器线程。 虽然可配置,但默认情况下CLR会让终结器运行2秒钟才会变得不耐烦; 如果超过此超时,则终止终结器线程,并且继续关闭而不会耗尽终结器队列的其余部分。

那么,是不是保证完成运行的析构函数?

虽然它不在您的代码中,但可能存在从Dispose()方法显式调用GC.SuppressFinalize的实例。 这压制了最终化,并且适用于不需要它的对象。

这可以显着提高性能,因为可终结的对象将始终存在于一个垃圾收集中,即它将被提升为gen1甚至gen2 GC,其具有与之相关的更高成本。

.NET没有析构函数。 您的代码包含终结器

当对象被垃圾收集时调用终结器,而不是在它被取消时调用。 它们的执行时间也有限,以防止悬挂物体。

另见https://en.wikipedia.org/wiki/Finalizer 。

另一种方法是在垃圾收集器释放内存时调用终结器。

但是,如果你有一个程序,它最多需要1Mb的内存但是在一台拥有10Mb内存的机器上运行,那么grabage collector的有效实现就是什么都不做(因为有足够的内存让程序执行)。 在这种情况下,永远不会调用终结器。