欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

如何判断对象可以被回收?

程序员文章站 2024-03-17 21:04:16
...

如何判断对象可以被回收?

里面存放着Java世界中几乎所有的对象实例,垃圾收集器对堆进行回收前,要做的第一件事情就是确定哪些对象还“活着”,哪些对象已经“死了”(即不可能再被任何途径使用)。


如何判断对象可以被回收?
我觉得《寻梦环游记》是一个很棒的电影,让我对人类的死亡有了新的认识:每个人其实都要经历两次死亡——当灵魂和肉体分离,这是是第1次死亡;被所有人遗忘,这是第2次死亡,也是彻底的死亡。


引用计数算法(Reference Countint)

在很多教科书中都介绍了这样一种判别对象是否死亡的算法:为对象添加一个引用计数器,每当有一个地方引用了对象,计数器的数值+1;每当有一个引用失效,计数器的数值-1;任何时刻,引用计数器数值为0的对象就是不可能在被使用的对象。

客观地说,引用计数算法实现简单,判定效率也很高,大多数情况下它都是一个不错的算法,也有很多比较著名的应用案例,但是,主流的JVM都没有选用引用计数算法来管理内存,其中最主要的原因是它很难解决对象之间相互循环引用的问题

下面的代码用于证明我现在使用的HotSpot虚拟机没有使用引用计数算法:

public class ReferenceCountingGC {
private static final int MB_1 = 1024 * 1024;
public Object instance = null;

/**
     * 这个成员属性的唯一意义就是占点内存,以便能在GC日志中看清楚是否被回收过。
     */
    private byte[] bigSize = new byte[2 * MB_1];

    /**
     * 验证JVM是否使用“引用计数器”判断对象能否回收
     */
    public static void testGC() {
        ReferenceCountingGC instanceA = new ReferenceCountingGC();
        ReferenceCountingGC instanceB = new ReferenceCountingGC();
        instanceA.instance = instanceB;
        instanceB.instance = instanceA;

        instanceA = null;
        instanceB = null;

        // 假设在这里发生GC,instanceA和instanceB是否能被回收?
        System.gc();
        /*
         * 若JVM采用“引用计数器”判断对象能否回收,由于instanceA和instanceB相互引用,
         * instanceA和instanceB的“被引用数”都不为0,因此,都不能被回收。
         */
    }

    public static void main(String[] args) {
        ReferenceCountingGC.testGC();
    }
}

设置虚拟机参数 -XX:+PrintGCDetails ,执行代码,控制台打印信息如下:

如何判断对象可以被回收?


可达性分析算法(Reachability Analysis)

在主流的商用程序语言(Java、C#等)的主流实现中,都是通过可达性分析来判定对象是否死亡。可达性分析算法的基本思路是:以一系列被称为“GC Roots”的对象为起点,寻找到达某个对象的路径,该路径被称为“引用链”,若引用链不存在,则认为此对象是不可用的。

如何判断对象可以被回收?

在Java语言中,可作为GC Roots 的对象包括下面几种:

  1. 虚拟机栈(栈帧中的本地变量表)中引用的对象。
  2. 方法区中类静态属性引用的对象。
  3. 方法区中常量引用的对象。
  4. 本地方法栈中JNI(即一般说的Native方法)引用的对象。

参考文献:

  1. 《深入理解Java虚拟机》
相关标签: Java虚拟机