Java基础学习之JVM篇:说说引用计数和三色标记清除算法

学习目标

在学习JVM中,我们重点在于认识和了解GC这块,而GC在前面Java基础学习之JVM篇:说说栈和堆的区别我们重点和大家一起学习了Java虚拟机的内存模型,在Java基础学习之JVM篇:说说STW、吞吐量中当然我们基本知道了GC的基本原理和作用,那么本节我们可以来一起了解GC的实现方式,也可以说是GC的算法实现。

  1. 了解引用计数
  2. 为什么需要三色标记而不是双色标记
  3. 三色标记如何处理mutation

引用计数

什么是引用计数?顾名思义就是这个对象被引用的次数,例如对象A被其它对象引用了两次,即计数2。
在这里插入图片描述

只要计数>0的将不会被GC回收,而计数为0的将被GC回收。例如上图中的对象B和C没有被其它对象引用,计数为0,那么在下次GC时将被回收。

其实引用计数在历史长河中存在了很长一段时间,但是它有着明显的缺陷。例如下面的引用:

public class EmptyObject {

    EmptyObject ref=null;
 
    public static void main(String[] argv){

        EmptyObject objectA=new EmptyObject();
        EmptyObject objectB=new EmptyObject();
        objectA.ref=objectB;
        objectB.ref=objectA;
        objectA=null;
        objectB=null;
    }

}

这里就是关于循环引用的问题,我们知道如果采用引用计数法,myObject1和myObject2将不能被回收,因为他们的引用计数无法为零,可以理解为如下图:
在这里插入图片描述
次数A和B引用计数都为2,当我们将objectA和objectB置为null后:
在这里插入图片描述
次数A和B计数为1,都不能被GC回收,陷入死循环。甚至在多线程中,引用计数都显得很不靠谱,引用计数也许在一个线程中被误以为清零,在另一个线程又开始计数,造成计数的不一致。那么是不是需要优化呢?

双色标记

我们在引用计数方法,发现会出现上述问题后,便有了一系列优化过程。比如Root tracing遍历即根节点遍历法,如果有对象的节点有联通路径到达根节点,那么即为有效,否则将会被回收,例如下图红色为不可达,将被回收。
在这里插入图片描述
其实可以分为两个阶段,所有节点初始过程都标记为红色,第一阶段在遍历过程中进行标记mark,可达标记为白色,第二阶段为sweep,包含需要finalize和不需要finalize的类。其实这里可以理解就是一种双色标记。真正的双色标记清除就是如此:
在这里插入图片描述
但是用着用着发现又有新的问题出现,比如下面的变动:

在这里插入图片描述
GC此时一边打扫,标记,清除,但这是其它线程又把原来的引用改动了。特别时在GC标记后,准备Sweep时,那问题就严重了,例如此时B引用的又指向了C。
在这里插入图片描述

三色标记

我们可以将已被Mark的节点记录状态,当被Mark的还被改了就是Mutation状态。记录到了这种状态后我们需要重新遍历标记。
在这里插入图片描述
那么我么怎么去处理Mutatin状态的节点去重新Mark呢?
可以添加一种颜色,就是一种状态,理解为未完成的任务,比如标记灰色状态的就是需要ReMark的。比如下面从C开始遍历,能到达的全部标黑。
在这里插入图片描述

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值