终结器中处置的资源与处置中释放的资源有什么区别

What is the difference between the resources disposed in a finalizer to those released in dispose

这是这个问题的后续问题:

Finalize/Dispose pattern in C#

所以我明白,如果我正在创建一个使用非托管资源的 class,我应该处置它们。链接问题中的答案说终结器处理非托管资源。但是,Dispose(Boolean) 方法也在处理非托管资源:

protected virtual void Dispose(bool disposing)
    {
        if (disposing)
        {
            // get rid of managed resources
        }   
        // get rid of unmanaged resources
    } 

那么finalizer的处置和dispose方法的处置有什么区别呢?

你会使用它的唯一原因(而且它极具争议性)。

  1. 终结器允许在对象被垃圾收集器删除之前清除它。 (也就是说,GC负责调用它,并从内存中清除对象)如果开发者忘记调用对象的Dispose()方法,那么将有可能释放非托管资源,从而避免泄漏。

不这样做的原因有很多,弄错的方法也有很多。简而言之,您几乎没有理由需要这样做或想要这样做

除了给定的答案:终结器在运行时由垃圾收集器调用。

所以你不能指望在终结器中释放非托管资源的时间!因为未知。

此外,finalizer 在另一个线程上运行,因此当垃圾收集完成时,finalization 可能仍然是 运行!所以必须通过另一个垃圾收集,才能完全摆脱一个对象。

因此,第一次垃圾回收调用 finalezrs,但未收集对象(以及该对象持有引用的对象),它将在第二次垃圾回收中被收集。

一个带有finalizer的对象会经历GC的两个阶段:第一次,finalizer是运行,第二次,对象被真正回收,内存被释放。除了增加 GC 压力和延迟内存释放回池外,终结器还具有处理字段可能不处于有效状态的对象的功能。此外,在终结器线程上抛出异常会立即破坏整个应用程序,而没有任何关于刚刚发生的事情的友好信息。

这就是为什么 Dispose 模式实现总是以调用 GC.SuppressFinalize 为特色,这导致终结器不 运行 以防对象已经被释放并且 GC 可以首先直接释放内存运行.

通常,如果您的应用程序应该在内存不足或线程中止以及随后的 AppDomain 卸载等严重异常中幸存下来,那么使用终结器可能会非常复杂和棘手 - SQL Server 或IIS.

长话短说:除非万不得已,否则不要使用终结器,如果必须(例如,使用非托管资源),还有很多研究等着您。

您可以在以下博客文章中找到有关此主题的更多阅读材料:

Eric Lippert - When everything you know is wrong

Joe Duffy - Never write a finalizer again