垃圾收集器为什么单独处理可终结的对象?

时间:2016-12-27 08:47:48

标签: c# .net garbage-collection clr

我正在阅读Jeffrey Richter的书“CLR via c#”。引自那里:

  

在GC对象的垃圾收集完成时调用Finalize方法   已经决定成为垃圾。这意味着无法回收这些对象的内存   因为Finalize方法可能会执行访问字段的代码。   因为可终结对象必须在集合中存活,所以它会被提升到另一代,从而强制对象   比他们的寿命要长得多

它误导了我一点点。为什么不能立即回收可终结的对象?我无法理解finalize方法可能执行访问字段的代码的论点。有什么问题?此外,我无法理解为什么可终结对象应该移动到老一代并存储在分离队列中(在其他终结器线程中处理)。

在我看来,最简单的方法是在没有这些额外操作的情况下完全移除之前完成对象。

2 个答案:

答案 0 :(得分:4)

  

为什么不能立即回收可终结的对象?我无法理解finalize方法可能执行访问字段的代码的论点。有什么问题?

  1. 因为Finalize()只是对象的常规方法,所以其中的代码可能会访问该对象的任何字段。

  2. 当垃圾收集发生时,所有线程都被冻结。

  3. 这两点加在一起,当gc发生时,它不能立即执行Finalize()方法(所有线程在gc期间暂停!!),而Finalize预计会在收集对象之前调用。

    以上所有这些都导致垃圾收集无法在调用Finalize()方法之前立即终止对象。所以gc将对象从“死亡列表”中取出(该对象现在被称为复活),并将其放入一个名为“Freachable”的队列中(“ F “代表最终确定,”可达“表示其中的所有对象现在都不能被垃圾收集,因为gc仅从根目录收集无法访问对象。”

    gc完成后,一个具有高优先级的特殊专用线程将从“Freachable”队列中取出每个条目并在其上调用Finalize()方法,这使得该对象最终“垃圾收集”,但当然,因为第一个gc已经在此Finalize()调用进程之前结束,所以从“Freachable”中出来的所有对象现在只能安排到下一个垃圾回收。

      

    此外,我无法理解为什么finalizable对象应该移动到老一代并存储在单独的队列中(在其他终结器线程中处理)。

    要理解这一点,您首先需要了解generation gc model的概念。在从“Freachable”队列中弹出对象并再次为垃圾收集做好准备之后,由于它们在前一个存档中存活,它们已经被移动到老一代。

答案 1 :(得分:0)

我认为这句话说"完成你的工作单元并杀死你的实例。要杀死你的实例,你应该因为你的记忆而清理你的垃圾收集。"