为什么CLR需要专用线程来调用finalize方法?

nav*_*een 6 c# garbage-collection

这是msdn文章的摘录.文章可以在这里找到

有一个特殊的运行时线程专用于调用Finalize方法.当可释放队列为空(通常是这种情况)时,该线程会休眠.但是当条目出现时,此线程会唤醒,从队列中删除每个条目,并调用每个对象的Finalize方法.因此,您不应该在Finalize方法中执行任何代码,该方法对正在执行代码的线程做出任何假设.例如,避免在Finalize方法中访问线程本地存储.

这是我之前提出过的一个问题,我对于同样的说法没有投票,即Finalizable对象没有专用线程,而且我的信息源是错误的.如果本文解释的是真的,我想知道为什么CLR需要一个特殊的线程来调用Finalize方法?

ang*_*son 3

终结器所做的事情不需要单独的线程,但是请考虑这一点:

  • 当 GC 在第 0 代和第 1 代(“短暂”代)上运行时,托管线程将被挂起
  • 托管线程恢复后,并发或后台收集可以在第 2 代上运行(MSDN 中有很多关于此的信息:垃圾收集基础知识

然而,一个看似简单的解决方案是执行以下操作:

  • 挂起所有线程(或者可能让触发 GC 的线程继续运行,只是让它执行 GC)
  • 进行垃圾收集,及其所需的一切
  • 恢复所有线程

这可能很容易实现。GC操作可以自由访问与堆相关的所有数据结构,并且可以自由地做任何它想做的事情,因为没有其他访问这些东西的线程正在运行。

然而,这会使程序时不时地出现“相当长”的停顿,这在大多数应用程序中是相当不可接受的。

因此,负责 GC 工作的团队选择了尽可能短时间挂起的解决方案,仅在需要时挂起(第 0 代和第 1 代收集),同时在收集第 2 代时让应用程序保持运行。这个就比较困难了。请注意,这是我的假设,我无法访问实际的设计文档或任何有关此的可靠信息。这些假设基于官方文档。

那么回到终结器线程。这些对象已经“死亡”并计划收集,因此代替上述设计决策,为什么要麻烦执行应用程序工作的主线程之一处理这个问题呢?由于 GC 已经在后台执行操作,因此以相同的方式处理死亡对象的终结似乎是一个不错的决定。