JVM--14 【垃圾回收机制】 如何判断对象是垃圾对象

一、对象已经死了吗?

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

判断对象是否存活的算法:引用计数法、可达性分析算法。这里分两篇博文介绍一下这两种算法,本篇先介绍一下:引用计数算法

二、引用计数算法    

            引用计数算法:给对象中添加一个引用计数器,每当有一个地方引用它时,计数器值就+1;当引用失效时,计数器值就-1;任何时刻计数器为0的对象就是不能再被使用的垃圾对象。

            引用计数算法的实现简单,判定效率高。在大部分情况下它都是一个不错的算法。但是,至少主流的Java虚拟机里面没有选用引用计数算法来管理内存,主要原因是它很难解决对象之间的相互循环引用的问题,这种情况下,即使断开了对象在虚拟机栈中的reference,引用计数器永远都不会为0,这样就会造成内存泄漏。下面举例说明:

            下面代码中对象g1和g2都有字段instance,赋值使g1.instance = g2  g2.instance = g1 除此之外,这两个对象再无任何引用,实际上这两个对象已经不可能再被访问,但是它们之间相互引用着对方,导致它们的引用计数都不为0,于是引用计数算法无法通知GC收集器回收它们。

package cc.mynatapp.detroitdentist.gc;

/**
 * @author Xu hao
 * @Description 判断对象是否存活算法:引用计数
 * 需要设置JVM参数:
 *      -verbose:gc    打印垃圾回收信息
 *      -xx:+PrintGCDetails 打印垃圾回收的详细信息
 * @Version 1.0
 * Email [email protected]
 * create on 2018/9/22
 */
public class GCStrategyRefCount {

    private Object instance;

    /**
     * 这里构造器的唯一意义就是占用点内存,以便能在GC日志中看清楚是否被回收过。
     **/
    public GCStrategyRefCount() {
        byte [] g = new byte[20 * 1024 * 1024];
    }

    public static void main(String[] args){

        GCStrategyRefCount g1 = new GCStrategyRefCount();
        GCStrategyRefCount g2 = new GCStrategyRefCount();
        // g1 g2 循环引用
        g1.instance = g2;
        g2.instance = g1;
        // 断掉Java栈中g1 g2的reference
        g1 = null;
        g2 = null;
        System.gc();

    }

}

               运行结果如下:

               从上面的结果中可以清楚看到,GC日志中包含“21054K->574K(31428K)”,21054-574=20480(刚好20M)这意味着虚拟机并没有因为这两个对象相互引用就不回收它们,这也从侧面说明HotSpot并没有通过引用计数算法来判断对象是否为垃圾对象(对象是否存活)。

猜你喜欢

转载自blog.csdn.net/PORSCHE_GT3RS/article/details/82811239