垃圾标记阶段算法之引用计数算法

垃圾标记阶段:对象存活判断

我们清楚在堆中存放着几乎所有的Java对象实例,在GC执行垃圾回收之前,首先需要区分出内存中哪些是存活对象,哪些是已经死亡的对象,只有被标记为已经死亡的对象,GC才会在执行垃圾回收时,释放掉其占用的内存空间,因此这个过程我们可以称为垃圾标记阶段。
那么在JVM中究竟是如何标记一个死亡对象?简单来说,当一个对象已经不再被任何的存活对象继续引用时,就可以宣判为已经死亡。判断对象存货一般有两种方式:引用计数算法和可达性分析算法。

引用计数算法

引用计数算法比较简单,对每一个对象保存一个整性的引用计数器属性,用于记录对象被引用的情况。对于一个对象A,只要有任何一个对象引用了A,则A的引用计数器就加1;当引用失效时,引用计数器就减1,只要对象A的引用计数器的值为0,即表示对象A不可能再被使用,可进行回收。

优点:实现简单,垃圾对象便于标识,判定效率高,回收没有延迟性
缺点:
1.它需要单独的字段存储计数器,这样的做法增加了存储空间的开销。
2.每次赋值都需要更新计数器,伴随着加法和减法操作,增加了时间开销。
3.引用计数器有一个严重问题,即无法处理循环引用的情况,如下图所示,这是一条致命缺陷,导致在Java的来集会收器中没有使用这类算法。
引用计数算法中致命缺陷——循环引用问题

验证Java中不适用引用计数算法

public class RefCountGC {
    //这个成员属性唯一的作用就是占用一点内存
    private byte[] bigSize = new byte[5 * 1024 * 1024];//5MB

    Object reference = null;

    public static void main(String[] args) {
        RefCountGC obj1 = new RefCountGC();
        RefCountGC obj2 = new RefCountGC();

        obj1.reference = obj2;
        obj2.reference = obj1;

        obj1 = null;
        obj2 = null;
        //显式的执行垃圾回收行为
        //这里发生GC,obj1和obj2能否被回收?
        System.gc();

        try {
            Thread.sleep(1000000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}

上面代码的图示如下
在这里插入图片描述
运行程序时,参数设置中增加参数-XX:+PrintGCDetails,会发现会进行GC,并且把上述的两个循环引用对象进行了回收。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值