关于java:jvm垃圾收集器对比实现原理解析

27次阅读

共计 2581 个字符,预计需要花费 7 分钟才能阅读完成。

  • Serial/Serial Old 收集器

这是两款最根本的垃圾回收器,个别用于客户端模式下,适宜单核或者配置较低的状况。

Serial: 新生代垃圾收集器,标记复制算法,单个垃圾收集线程,会产生 Stop The World

Serial Old:老年代垃圾收集器,标记 - 整顿算法,单个垃圾收集线程,Stop The World,可作为 CMS 收集器并发失败时的后备预案

  • Par New / Parallel Old 收集器

相比于 Serial/Serial Old,这两款垃圾收集器也很相似,次要区别是引入了多个垃圾收集线程,但收集的时候依然是须要 Stop The World 的,无奈与用户线程并发

Par New : 新生代垃圾收集器,标记复制算法,多个垃圾收集线程,Stop The World,常常与 CMS 垃圾收集器搭配应用

Parallel Old: 老年代垃圾收集器,标记整顿算法,多个垃圾收集线程,Stop The World, 与 Paralle Scavenge 收集器搭配应用

  • Parallel Scavenge 收集器

新生代垃圾收集器,与 Parallel Old 搭配应用,与 Par New 相似,采纳多个垃圾收集线程,会产生 Stop The World,然而绝对于 Par New,它有着一些独特的特点,劣势

首先它是一款以吞吐量优先的垃圾收集器,能够通过 -XX:GGTimeRatio,来达到设置吞吐量的目标。另一个特点是它有一个自适应调节策略,可通过 -XX:UseAdaptiveSizePolicy 这个开关参数开启自适应调节,开启后它将主动调节新生代大小,Eden 与 Survivor 的比例,降职老年代对象大小等参数值,从而尽量满足设置的吞吐量参数或者进展工夫参数

  • CMS(Concurrent Mark Sweep)收集器

老年代垃圾收集器,与 Par New 搭配应用。它是一款以最小回收进展工夫优先的垃圾收集器,也是 Hotspot 第一款真正采纳并发收集算法的垃圾收集器。采纳了标记 - 革除算法,在标记阶段利用增量更新解决并发标记问题。其毛病也很显著,会产生大量的内存碎片,且吞吐量也不高。在进行 Full GC 时会对内存碎片利用整顿算法进行整顿(会 Stop The World)。并发革除阶段可能用户线程会没有足够的内存空间调配对象,导致调配失败,此时会以 Serial Old 收集器作为调配失败的后备预案(会 Stop The World)

  • G1(Garbage First)收集器

以 CMS 收集器替代者的身份呈现,同样以最小回收进展工夫为指标,是 JDK9 的默认垃圾收集器(JDK8 是 Parallel Scanvenge + Parallel Old 组合)。它创始了以部分收集思维和面向 Region 的内存布局,以 Region 做为最小回收单元,多个 Region 组成回收机 CSet。同样,这款垃圾收集器中也蕴含着分代收集思维,不过不同于之间的收集器将堆内存划分为新生代,老年代的布局。G1 将堆空间按固定大小(1M-32M 可通过启动参数设定)划分为多个 Region,每个 Region 都能够依据须要作为新生代(Eden,Survivor),老年代 (Old),或者说大对象(Humongous,大小超过 Region 一半,当做老年代看待)

G1 的特点是建设了进展工夫模型:在 M 毫秒的工夫片内 耗费在垃圾收集上的工夫不超过 N 毫,通过启动参数 +XX:MaxGCPauseMillis 可指定最大进展工夫

实现原理:在垃圾收集过程中,记录每个 Region 回收耗时等信息,计算出平均值,标准偏差,置信度等统计信息,从而预测出由哪些 Region 组成的回收集才能够在不超过设置的进展工夫束缚下取得最高的收益。

G1 的收集过程如上图所示。其主保障并发标记正确性的解决方案是原始快照(SATB,区别于 CMS 的增量更新),在筛选回收阶段更新 Region 统计数据,依据回收价值排序,抉择回收集,回收。所以从整体上看,G1 还是基于标记 - 整顿算法的,只实现了标记阶段的与用户线程并发,回收阶段还是要 Stop The World。这种形式导致其没有内存碎片问题。但如果能实现其整顿阶段的并发,速度就更快了(其实,整顿阶段的并发实现还是比价难得,在起初的 Shenandoah 和 ZGC 收集器便实现了整顿阶段的并发)

  • Shenandoah 收集器

这是一款低提早垃圾收集器,其指标是在尽可能对吞吐量影响不大的前提下,实现在任何堆内存大小下都能够把垃圾收集工夫限度在 10ms 以内。它是 OpenJDK12 正式个性之一,和 G1 收集器有很多相似之处,甚至专用了一部分源代码。相比之下,它有许多的改良点。比方实现了并发的整顿算法,用连贯矩阵代替了 G1 的记忆集。要实现并发整顿却有一个十分大的难点:与用户线程并发的状况下挪动对象,用户线程可能在收集线程挪动过程中对被挪动的对象进行读写访问。Shenandoah 采取的解决方案是读屏障 + 转发指针

​ 读屏障:能够了解为虚拟机层面对对象拜访操作的 AOP 切面,说白了就是在拜访对象之前要干点什么事;转发指针:在原有对象布局构造的最后面对立加一个援用字段,在不处于并发挪动的状况下,该援用指向对象本人。当对象有了一份新的正本时,只需批改该援用值指向新的正本,虚拟机对旧对向的拜访就会转发到新对象下来

  • ZGC 收集器

它也是一款低提早收集器,指标同 Shenandoah 一样,从目前的体现来看,比 Shenandoah 更弱小,是 JDK11 公布的一款垃圾收集器。它的特点是 Region 具备动态性—动态创建和销毁,动静的区域容量大小。此外它同样实现了并发的整顿算法。其实现计划是:染色指针 + 多重映射

染色指针:将大量额定的信息间接存储在指针上,在 64 位操作系统中,Linux 零碎只反对 46 位的物理地址空间(64TB),染色指针将这 46 位中的 4 位拿进去存储 4 个标记信息:如对象的三色标记状态、是否进入重调配集(被挪动过)等信息;多重映射:因为处理器可不意识地址中哪几位是真是的寻址地址,哪几位是标记位,所以 Hotspot 就通过多重映射技术对地址做一个映射,将寻址地址雷同,标记位不同的援用都映射到同一块物理地址空间上。

​ ZGC 收集器仅从援用上就能够判断一个对象是否处于重调配集中(回收集),若用户拜访了重调配集中的对象,将被内存屏障截获,而后依据 Region 上的转发表将申请转发到新复制的对象上,同时修改援用值,使其指向新对象。

正文完
 0