从根沿引用前进

根是运行时已知仍可能被程序直接使用的入口,例如栈、寄存器或全局状态中的引用。追踪从这些入口向外扩展,判断的是可到达性,不是对象未来是否真的还会被使用。

甲乙相互引用而外部再无入口时,它们仍可以一起被判为不可到达。与单纯引用计数不同,追踪不要求先找到一个计数为零的对象才能开始回收。

参考:[1] [2]

对象图变化时的协调

程序线程与回收器同时工作时,引用可能在扫描期间改变。Go 的实现说明把工作划分为标记准备、并发标记、标记终止及清扫等阶段,并利用写屏障和短暂的全局停顿维持安全条件。

因此,“并发回收”不等于没有停顿,也不等于不消耗应用的处理器资源。屏障、后台工作及分配时协助回收,都属于为缩短集中停顿而分散的成本。

参考:[1]

本轮保留下来的垃圾

Oracle 对历史 CMS 回收器的说明讨论了浮动垃圾:对象在扫描时仍可到达,随后才失去引用,本轮可能保留它,到后续回收周期再处理。这个例子说明并发策略可以安全地多留对象。

回收器的正确性首先要求不释放仍可能使用的对象。缩短停顿、提高吞吐、减少额外内存和更快归还空间之间存在取舍;某个实现的阶段安排不能直接代表所有追踪式回收器。

参考:[2]