2011-04-11 30 views
10

据我了解,在C#垃圾回收器会放一个类的所有对象到结束队列,只要我实现类的析构函数。当我正在阅读GC.Suppresfinalize的文档时,它提到对象头文件已经有一些设置用于调用finalize。GC为什么要将对象放入最终队列中?

我想知道的是,为什么GC的实施者不得不把所有的对象在队列中,并通过1-2个周期延迟的内存freeup。难道他们不能在释放内存时查看位标志,然后调用对象的finalize并释放内存?

毫无疑问,我是一个白痴,我不能够理解GC的工作。我提出这个问题只是为了提高我的理解,或者填补我的知识缺失

编辑:如果位标志是用于suppressfinalize,GC实现者可能已经在此对象头中添加了另一个标志,不是吗?

+0

哪个实现? – R0MANARMY 2011-04-11 23:45:30

+0

垃圾回收.. – paseena 2011-04-11 23:46:30

+1

我认为@ R0MANARMY表示哪个GC实现。 Universe中有多个.NET框架的实现。无论如何,哪个实现应该没有关系,因为问题是关于为什么* GC实现会实现终结器队列。 – 2011-04-11 23:49:08

回答

11

因此,它可以在不同的线程运行,从而堵塞了主GC线程保持。

你可以学到很多关于此MSDN article的GC。

1

这是理想的垃圾收集暂停要尽可能的短。为此,当垃圾收集的疯狂工作完成时,运行终结器通常会延迟到稍后的时间。它是在单独的线程中在后台完成的。

+0

这个问题不仅仅是暂停的问题之一,为了允许存在任意深度的对象图,许多GC重新使用对象内的内存来跟踪其进度。他们这样做的方式可以在GC完成时撤销,但在GC运行时,许多对象将处于完全不适合运行正常代码的状态。 – supercat 2015-12-16 20:24:34

0

@Jason:对于f-reachable队列是如此。但恕我直言,它并没有解释为什么有自己的定稿队列

我的猜测是,终结队列有加另一个信息,帮助GC 所有对象的生命周期的可能状态之间进行区分。

对象头部中的终结标志表示“对象需要终结”或“对象不需要终结”,但并不表示终止是否已经发生。

但说实话,我不明白为什么它需要在当前的定稿过程实施。

事实上,这里是天真的流程我想可能没有终结队列:

  • 创建对象时,如果它有一个终结,则GC设置结束标志;
  • 如果后来SupressFinalize被调用,那么该标志被归零;
  • 现在让我们跳到GC收集对象的方式,该对象从任何地方都没有被引用:如果设置了终结标记,则GC将该对象的引用放入f-reachable队列,并让终结线程运行;
  • 后来终结线程退出引用,重置终结标志并运行终结器;
  • 如果对象想要重新设定以后它可以ReRegisterForFinalize重新设置终止标志;
  • 后来GC再次收集对象:如果没有设置终结标志,它知道没有什么要做,然后释放对象内存;
  • 如果设置了终结标志,则GC再次将该对象的引用排入f可到达的队列,然后再次进入另一轮;
  • 在某个时间点对象很高兴,完成定稿并收集;或者应用程序域或进程被关闭并且无论如何都释放内存。

因此,似乎在这些情况下不需要定型队列,只有定型标志是有用的。

一个可能的原因是,从概念的角度来看,可能会有一条规则:“一个对象被收集,当且仅当它没有被任何根引用”。 因此,没有确定队列,并且根据对象状态本身收集对象的决定,检查确定标志,与此规则不兼容。

但是我真的不认为GC的实现是基于这种理论规则的教条性应用,而只是基于实用的选择;所以很明显,我错过了一些关键场景,其中GC需要确定队列才能知道在收集对象时要做什么,但是哪些是

+0

您预先设定GC查看收集的每个对象。这是没有必要的,并且使其高效需要向每个对象的头添加额外的四个字节。 – supercat 2013-10-10 20:57:16

+0

@超级猫:对不起,但我没有明白你的意思;对我来说,GC必须“查看”它收集的对象,至少要知道它是否必须将它们推送到f-reachable队列中,或者是否可以删除它们的内存。为什么四个字节?用于存储散列?因为对于一个二进制标志,我想在对象的头文件中还有一些空闲位。那么你能否详细说明这些问题?谢谢。 :) – Pragmateek 2013-10-10 21:28:41

+1

每个有终结器的对象在收集之前都必须查看,但是如果GC有一个包含终结器的所有对象的列表,它只能*查看该列表中的内容。每个活动对象都带有一个终结器,每个GC周期都必须查看两次,但死亡对象根本不会被检查。 – supercat 2013-10-11 00:22:36

1

垃圾收集器不会识别和检查垃圾,除了处理大对象堆时。相反,它的行为就像一个保龄球胡同的取样器,可以在抛掷之间去除死木:取样器抓住仍然存在的所有销钉,将它们从车道表面提起,然后在整个车道上运行清扫杆,而不考虑表面上有多少针脚。清除内存批量比识别要删除的单个对象快得多。如果1%的对象具有终结器(实数可能更少),那么有必要检查100个对象标题以找到每个可终结对象。有一个单独的具有终结器的对象列表使得GC甚至无需查看任何不包含的垃圾对象。

+1

嗡嗡声,有趣的点和类比。 :) – Pragmateek 2013-10-11 22:15:55

相关问题