在 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 方法是最后一个逃生门,执行过程中如果重新变的可达,就会在第二次标记时移出队列,第二次标记之后,队列中的对象都会被回收。

10-11 18:06