还有一种情况多标,比如 A 变成黑色之后,根引用被 mutator 删除了,那其实 A 就属于垃圾,但是已经被标记为黑色了,那就得等下次 GC 清除了。
这其实就是标记过程中没有暂停 mutator 而导致的,但这也是为了让 GC 减少对应用程序运行的影响。
多标其实还能接受,漏标的话就必须处理了,我们可以总结一下为什么会发生漏标:
mutator 插入黑色对象 A 到白色对象 C 的一个引用
mutator 删除了灰色对象 B 到白色对象 C 的一个引用
只要打破这两个条件任意一个就不会发生漏标的情况。
这时候可以通过以下手段来打破两个条件:
利用写屏障在黑色引用白色对象时候,将白色对象置为灰色,这叫增量更新。
利用写屏障在灰色对象删除对白色对象的引用时,将白色对象置为灰,其实就是保存旧的引用关系。这叫STAB(snapshot-at-the-beginning)。
总结至此有关垃圾回收的关键点和思路都差不多了,具体有关 JVM 的垃圾回收器等我下篇再作分析。
现在我们再来总结一下。
关于垃圾回收首先得找出垃圾,而找出垃圾分为两个流派,一个是引用计数,一个是可达性分析。
引用计数垃圾回收的及时,对内存较友好,但是循环引用无法处理。
可达性分析基本上是现代垃圾回收的核心选择,但是由于需要统一回收比较耗时,容易影响应用的正常运行。
所以可达性分析的研究方向就是往如何减少对应用程序运行的影响即减少 STW(stop the world) 的时间。
因此根据对象分代假说研究出了分代收集,根据对象的特性划分了新生代和老年代,采取不同的收集算法,提升回收的效率。
想方设法的拆解 GC 的步骤使得可以与应用线程并发,并且采取并行收集,加快收集速度。
还有往评估的方向的延迟回收或者说回收部分垃圾来减少 STW 的时间。
总的而言垃圾回收还是很复杂的,因为有很多细节,我这篇就是浅显的纸上谈兵,不要被我的标题骗了哈哈哈哈。
最后这篇文章写了挺久的,主要是内容很多如何编排有点难,我也选择性的剪了很多了,但还是近 1W 字。
期间也查阅了很多资料,不过个人能力有限,如果有纰漏的地方请抓紧联系我。
巨人的肩膀https://openjdk.java.net/groups/hotspot/docs/HotSpotGlossary.html
《The Garbage Collection Handbook 》
https://www.iteye.com/blog/user/rednaxelafx R大的博客
https://www.jianshu.com/u/90ab66c248e6 占小狼的博客
微信搜索【yes的练级攻略】,关注 yes,从一点点到亿点点,我们下篇见。