谈到垃圾回收,就不得不说如何判断一个对象是不是垃圾?是否能够在本次收集流动中清理掉?所以就须要一种算法来判断一个对象是应该生存还是死亡。目前次要有两种算法,一种是援用计数法(python 语言采纳此算法),另一种就是这里要讲的可达性剖析算法(java,c# 等语言)
- 次要思路 可达性剖析算法的次要思路是先找出一批根节点对象汇合作为 GC Roots(可称为根节点枚举),而后从这批根节点登程,查找其援用关系(相似于深度优先搜寻),最终造成如下图这样的反映对象间依赖关系的图,若某些对象没有任何援用链与 GC Roots 相连(如下图中的 Object5,Object6,Object7),则阐明这些对象就是垃圾对象,是能够被垃圾收集器回收的。
- GC Roots
如下这些对象就能够作为 GC Roots 对象:
虚拟机栈中援用的对象(参数,局部变量等)
办法区中类动态变量
办法区中常量援用的对象
本地办法栈中援用的对象
被同步锁(synchronized)持有的对象
JMXBean 等
- 实现原理
从思路上来看,可达性剖析算法很简略,就两步,第一步找出 GC Roots,第二步从 GC Roots 开始向下遍历整个对象图。但在真正的实现中,还是有很多中央值得注意的。
就拿根节点枚举来说。整个办法区那么多类,常量信息,若一个一个来查看那些可做 GC Roots,消耗的工夫必定不少,所以在 HotSpot 虚拟机中就通过一组 OopMap 的数据结构来记录哪些地位是援用,在类加载实现后就将哪个对象内什么偏移量上是什么数据类型计算出来,这样收集器就能够间接得悉这些信息,而不须要顺次遍历整个办法区。
而第二步从 GC Roots 向下遍历对象图则有很多优化措施,例如,如何让用户线程与垃圾收集线程并发运行?并发运行会产生什么问题?有哪些解决方案?
对于 CMS 收集器是通过增量更新来解决并发标记问题的,而 G1,ShenanDoah 垃圾收集器则是通过原始快照来(Snapshot At The Beginning,SATB)解决并发标记问题。这两种解决方案别离是毁坏了会导致并发标记产生问题的两个必要条件之一。至于这两个必要条件是啥,可参考三色标记实践。