【JVM】垃圾回收机制

垃圾回收三大步骤:判断是不是垃圾(垃圾判断算法) -> 标记需要回收的垃圾(三色标记) -> 回收垃圾(垃圾回收算法)。

一、如何判断是不是垃圾(垃圾判断算法)?

(1)引用计数器算法:对象中记录引用次数(引用就++,引用失效--),此方式无法判断循环依赖的引用问题。

(2)可达性分析算法:将一些对象作为GC根向下搜索,无法被搜索到的说明无引用可回收。

        GC根:比如栈帧中本地变量表引用的对象、方法区静态属性或常量引用的对象、本地方法(Nativie)栈引用的对象等等。

二、如何标记需要回收的垃圾(三色标记)?

(一)三色标记四个步骤

        a. 初始标记阶段:STW,只标记GC根直接关联的对象,耗时极少。

        b. 并发标记阶段:由GC根依次向下标记所有关联的对象,可达为存活对象,不可达为可回收对象。

        c. 重新标记阶段:STW,标记新建的对象引用(GMC收集器通过读写屏障+增量更新记录新建的引用对象)。

        d. 清除标记阶段:GC线程与用户线程并发清理被标记的垃圾对象。

三色标记遍历过程
三色标记遍历过程
  • 白色:尚未被GC扫描过的对象;
  • 灰色:被CG访问过但其直接引用的对象未被访问过(不可回收,全部访问后变成黑色);
  • 黑色:被GC访问过且其直接引用的对象也全都被访问过(非垃圾对象)。

 (二)三色标记的问题

  • 多标:A→B→C,A黑B灰C白时,A→B引用断了。(不用考虑,因为下一次可能被CG)
  • 少标/漏标:A→B,A黑B黑时,突然新增了B→C。(C变成浮动垃圾了)

(少标/漏标)解决方案:

  • 读屏障+重新标记:并发结束后STW重新标记新增的引用;
  • 写屏障+增量更新:将新增的引用加入待扫描的集合中;
  • 写屏障+原始快照:引用关系变化时记录之前的引用关系快照,扫描旧的对象再次标记。

三、如何回收垃圾(垃圾回收算法)?

(一)垃圾回收的算法

  • 标记-清除算法:效率低、容易产生大量空间碎片;
  • 标记-复制算法:无碎片、但浪费一半的内存;(新生代回收算法)
  • 标记-整理算法:先标记对象,然后让存活对象向一端移动,最后清理掉存活对象边界外的内存;
  • 分代收集算法:内存划分为新生代(1/3)和老年代(2/3),新生代采用标记-复制算法,老年代采用标记-整理/清除。

 (二)分代收集算法

        新生代默认内存分配比:Enden:From:To=8:1:1

        进入老年代条件:

        (1)15次GC依旧存活的对象;

        (2)大对象:大小占Eden区的一半;

        (3)空间分配担保:检查老年代最大可用内存是否大于新生代所有对象之和,成立(未开启则Full GC)则检查老年代空间是否大于历史晋升对象的平均大小,是则Minor GC;

        (4)动态年龄判断:Survivor区(From或To)相同年龄对象的大小>Survivor区的一半,年龄大于此值的可以直接进入老年代。

        老年代和新生代之间引用的解决方案:记忆集(卡表)。

四、垃圾收集器

(一)G1垃圾收集器

G1将堆分成很多个Region,每个Region只有在使用时才会确定其唯一角色(Eden、From/To、Old区、humongous区)

回收某个region的价值大小 = 回收获得的空间大小 + 回收所需时间。

(二)ZGC垃圾收集器 

ZGC:Region分为小、中、大三种,染色指针。

染色指针:对象的三色标记状态(Marked0、Marked1)、是否进入了重分配集(Remapped)、是否需要通过 finalize 方法来访问到(Finalizable)。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值