在 Java 中,是通过可达性分析来判断对象是否存活的。该算法的基本思路是以一系列名为GC Roots的对象作为起始点,从这些节点开始向下搜索,搜索所走过的路径称为引用链Reference Chain,当一个对象到GC Roots没有任何引用链相连时(用图论的话来说就是GC Roots到这个对象不可达),则证明此对象时不可用的。
能成为GC Roots的对象包括下面几种:
栈帧中的局部变量表中的引用的对象。
方法区中的类静态属性引用的对象。
方法区中的常量引用的对象。
Native 方法引用的对象。
【为何不用引用计数法?】
引用计数算法:每当一个引用指向该对象,计数器的值就 +1,引用失效计数器的值就 -1。
引用计数算法很难解决循环引用的问题。循环引用举例:
public class ReferenceCountingGC { public Object instance = null; public static void testGC() { ReferenceCountingGC objA = new ReferenceCountingGC(); ReferenceCountingGC objB = new ReferenceCountingGC(); objA.instance = objB; objB.instance = objA; objA = null; objB = null; } }上述代码中,到最后虽然 objA 和 objB 都为 null,但是两个对象的 instance 引用还都指向对方,导致这两个对象的引用计数器的值都为 1,无法回收。
【不可达对象的回收过程】
首先进行第一次标记,标记所有的不可达对象,在下次 GC 之前会执行对象的 finalize 方法。
没有重写 finalize 方法或 finalize 方法已经被虚拟机调用过的对象被直接清除。
重写 finalize 方法并且尚未调用的对象,将被放进一个队列中,稍后触发 finalize 方法。
finalize 方法是最后一个逃生门,执行过程中如果重新变的可达,就会在第二次标记时移出队列,第二次标记之后,队列中的对象都会被回收。