据我所知,一旦我实现了类的析构函数,c#中的垃圾收集器就会将类的所有对象放入终结队列中。当我阅读GC.Suppresfinalize的文档时,它提到对象头已经设置了一个用于调用finalize的位。
我想知道为什么GC的实现者必须将所有对象放入队列中,并将内存释放延迟1-2个周期。他们不能只是在释放内存时查看位标志,然后调用对象的finalize然后释放内存?
毫无疑问,我是一个白痴,我无法理解GC的工作。我提出这个问题只是为了提高我的理解或填补我知识中缺失的空白
编辑:如果位标志用于suppressfinalize,GC实现者可能为此目的在对象头中添加了另一个标志,不是吗?
答案 0 :(得分:12)
因此它可以在不同的线程中运行,从而防止阻塞主GC线程。
您可以从MSDN article了解GC的很多内容。
答案 1 :(得分:4)
这里有一个很好的解释
What are the Finalizer Queue and Control+ThreadMethodEntry?
基本上,推理可能并不总是理想的GC必须等待终结器代码执行,因此排队终结器允许推迟推迟到更方便的时候。
答案 2 :(得分:1)
垃圾收集暂停最好尽可能短。为此,运行终结器通常会延迟到稍后的时间,此时垃圾收集的疯狂工作已经完成。而是在后台完成一个单独的线程。
答案 3 :(得分:1)
@Jason:对于 f-reachable queue ,情况属实。但恕我直言,它没有解释为什么有终结队列本身。
我的猜测是,终结队列可以添加其他信息,帮助GC区分对象生命的所有可能状态 - 周期强>
对象标题中的终结标志表示“对象需要最终确定”或“对象不需要最终确定”,但它没有说明是否已经完成了最终化。
但说实话,我不明白为什么在当前的最终确定流程实施中需要它。
事实上,这是我想象的可能没有终结队列的天真工作流程:
所以在这些场景中似乎不需要终结队列,只有终结标志才有用。
一个可能的原因是,从概念的角度来看,可能存在如下规则:“当且仅当未从任何根引用时才收集对象”。 因此,没有最终化队列,并且基于对象状态本身收集对象的决定,检查终结标志,与此规则不兼容。
但实际上我并不认为GC的实施是基于这种理论规则的教条式应用,而只是基于实用的选择;所以很明显我错过了一些关键场景,GC需要终结队列来知道在收集对象时该做什么,但是哪些?
答案 4 :(得分:1)
垃圾收集器不识别和检查垃圾,除非处理大对象堆。相反,它的行为就像一个保龄球场置瓶机去除投掷之间的枯木:置瓶机抓住所有仍然站立的别针,将它们从车道表面抬起,然后在不考虑的情况下穿过车道的清扫杆表面上有多少个针脚。扫除内存批发比识别要删除的单个对象要快得多。如果1%的对象具有终结器(实数可能更少),那么有必要检查100个对象头以找到每个可终结对象。拥有一个单独的具有终结器的对象列表使得GC不必查看任何没有终结器的垃圾对象。