服务器之家:专注于VPS、云服务器配置技术及软件下载分享
分类导航

PHP教程|ASP.NET教程|Java教程|ASP教程|编程技术|正则表达式|C/C++|IOS|C#|Swift|Android|VB|R语言|JavaScript|易语言|vb.net|

服务器之家 - 编程语言 - Java教程 - 九款常见的 JVM 垃圾回收器

九款常见的 JVM 垃圾回收器

2024-03-12 20:12猿java Java教程

垃圾回收器作为 JVM中核心的一环,了解它的原理,可以帮助我们更好地调优和故障排除,因此,今天我们就来聊聊 JVM中 9款常见的垃圾回收器。

JVM 不仅是大厂面试的一个高频问题,也是 Java程序员跨入高职级必须掌握的知识点,垃圾回收器作为 JVM中核心的一环,了解它的原理,可以帮助我们更好地调优和故障排除,因此,今天我们就来聊聊 JVM中 9款常见的垃圾回收器。

九款常见的 JVM 垃圾回收器

背景 

因为 Java虚拟机的类型比较多,如果没有特殊说明,本文特指 HotSpot虚拟机,在分享回收器之前,我们首先对 HotSpot 虚拟机背景做个简单的介绍。

HotSpot VM,最初是由 “Longview Technologies” 这家小公司设计,并且一开始也不是为 Java语言研发。

1997年,Sun公司收购了这家公司,从而也就得到了 HotSpot虚拟机,在 Sun公司的一番优化下,HotSpot 虚拟机就成了 Sun/OracleJDK 和 OpenJDK共同的默认虚拟机。

2010年,Oracle 收购 Sun公司,HotSpot 虚拟机也就顺理成章成为了 Oracle旗下产品。

Sun/OracleJDK 和 OpenJDK 都是 Oracle 旗下产品,Sun/OracleJDK 是商用版,OpenJDK 是免费版,两款虚拟机的内核是一样,只是功能略有差异。

关于使用的是 Sun/OracleJDK 还是 OpenJDK ,可以通过 java -version 指令查看。

Sun/OracleJDK:

九款常见的 JVM 垃圾回收器

OpenJDK:

九款常见的 JVM 垃圾回收器

1.Serial 

Serial 收集器,见名知意,它是一个单线程的收集器,而且在进行垃圾回收时还必须暂停其它的工作线程,直到它收集结束(Stop The World)。

在 JDK 1.3.1 之前,它是 HotSpot虚拟机年轻代收集器的唯一选择。

Serial(年轻代) 和 Serial Old(老年代) 组合模式下,收集器大致的工作流程如下图:

九款常见的 JVM 垃圾回收器

尽管 Serial 收集器是单线程回收,并且会暂停其它的工作线程,看起来性能很差,但是,它依然是 HotSpot 虚拟机运行在客户端模式下的默认新生代收集器,因为相对于其它收集器的单线程,Serial 收集器消耗的内存最低,加上没有多线程交互的开销,反而使得它简单高效。

在启动 Java进程时,可以通过设置 -XX:+UseSerialGC  -XX:+UseSerialOldGC 参数,使用上述回收器组合。

2.ParNew

ParNew 收集器是 Serial 收集器的多线程并行版本,除了使用多线程进行垃圾回收之外,其它的行为和 Serial 收集器都是相同的。主要应用在 HotSpot虚拟机运行在服务端模式下的场景。

ParNew(年轻代) 和 Serial Old(老年代) 组合模式下,收集器大致的工作流程如下图:

九款常见的 JVM 垃圾回收器

在启动 Java进程时,可以通过设置 -XX:+UseParNewGC  -XX:+UseSerialOldGC 参数,使用上述回收器组合。

3.Parallel Scavenge 

Parallel Scavenge 收集器也是一款用于年轻代的回收器,它和 ParNew 收集器一样,采用多线程并发回收,但是,Parallel Scavenge可以通过 -XX:MaxGCPauseMillis 参数设置 GC的最大停顿时间,这样就可以达到一个吞吐量(Throughput)可控的目标,从而优于 ParNew回收器。

Parallel Scavenge(年轻代) 和 Serial Old(老年代) 组合模式下,收集器大致的工作流程如下图:

九款常见的 JVM 垃圾回收器

在启动 Java进程时,可以通过设置 -XX:+UseParallelGC  -XX:+UseSerailOldGC 参数,使用上述回收器组合。

但是,这种组合看起来很尴尬,年轻代使用的多线程并发收集,而老年代却使用单线程进行回收,怎么看起来老年代的回收都是“拖累”,因此,用于老年代的Parallel Old 并发收集器就诞生了。

Parallel Scavenge(年轻代) 和 Parallel Old(老年代) 组合模式下,收集器大致的工作流程如下图:

九款常见的 JVM 垃圾回收器

在启动 Java进程时,可以通过设置 -XX:+UseParallelGC  -XX:+UseParallelOldGC 参数,使用上述回收器组合。

4.Serial Old 

Serial Old 收集器是 Serial 的老年代版本,它也是一个单线程收集器,使用‘标记-整理’算法,和 Serial 收集器一样也是用于 HotSpot客户端模式。

Serial(年轻代) 和 Serial Old(老年代) 组合模式下,收集器大致的工作流程如下图:

九款常见的 JVM 垃圾回收器

在启动 Java进程时,可以通过设置 -XX:+UseSerialGC  -XX:+UseSerialOldGC 参数,使用上述回收器组合。

5.Parallel Old

Parallel Old 收集器是从 JDK 6 开始提供支持的,它是 Parallel Scavenge 收集器的老年代版本,支持多线程并发收集,采用‘标记-整理’算法。Parallel Old 收集器的出现,真正意义上实现了“吞吐量优先”的目标。

Parallel Scavenge(年轻代) 和 Parallel Old(老年代) 组合模式下,收集器大致的工作流程如下图:

九款常见的 JVM 垃圾回收器

在启动 Java进程时,可以通过设置 -XX:+UseParallelGC  -XX:+UseParallelOldGC 参数,使用上述回收器组合。

6.CMS

CMS 收集器,从 JDK5发布之后正式诞生,可以毫不夸张地说:CMS是一个跨时代的收集器,曾几何时,它是各互联网大厂面试中垃圾回收器的必问知识点。

CMS 是 Comcurrent Mark Sweep 的简称,用于老年代的垃圾回收。CMS的收集过程包含 5个步骤:

  • Initial Mark(初始标记) Stop The World
  • Concurrent Marking(并发标记)
  • Remark(重复标记) Stop The World
  • Concurrent Sweep(并发清除)
  • Resetting(重置)

CMS 收集器大致的工作流程如下图:

九款常见的 JVM 垃圾回收器

尽管 CMS回收器实现了回收线程与应用线程能同时并发工作的目标,但它也有致命的问题:无法处理“浮动垃圾”,有可能出现 Concurrent Mode Failure 失败,导致Full GC。因此,Oracle官方目前已经将 CMS 申明为 “deprecated”,不推荐使用。这也宣告了 CMS收集器的历史使命已结束。 

在启动 Java进程时,可以通过设置-XX:+UseConcMarkSweepGC 参数,显示使用 CMS回收器。

7.G1 

G1 回收器是 Garbage First 的简称, 它是一款面向服务器的垃圾回收器,用于大内存的多处理器计算机,目标是实现低延时垃圾回收。

从 Oracle JDK 7 Update 4 及更高版本已完全支持 G1,并且  JDK9 开始,G1 已经成为了默认的垃圾收集器。

应该说,G1是垃圾回收器历史上的一个里程碑,开启了基于 Region回收的时代,和以往的垃圾回收器不一样,G1尽管依然保留了年轻代和老年代的概念,但是各代存储地址是不连续的,每一代包含了 n个大小相同且不连续的 Region,G1 的堆内存分配如下图:

九款常见的 JVM 垃圾回收器

G1提供了两种 GC模式:Young GC和 Mixed GC。

G1的收集过程包含 4个步骤:

(1) Initial Marking(初始标记):标记了从 GC Root开始直接可达的对象

(2) Concurrent Marking(并发标记):在整个堆上查找活动对象,标记全部可达对象。这个阶段可能会被年轻代垃圾回收中断。

(3) Remark(重新标记):完成对堆中活动对象的标记。使用一种称为“快照在开始时”(Snapshot-at-the-Beginning,SATB)的算法,其速度比 CMS收集器中使用的算法要快得多。

(4) Cleanup(清除垃圾):该过程完成 3个事情

  • 对活动对象和完全释放的区域进行记账。(Stop The World) 
  • 清理已记住的集合。(Stop The World) 
  • 重置空的区域并将其返回到空闲列表。(并发执行)

G1 收集器大致的工作流程如下图:

九款常见的 JVM 垃圾回收器

在启动 Java进程时,可以通过设置 -XX:+UseG1GC 参数,显示使用 G1回收器。

8.Shenandoah

Shenandoah 也是一款 HotSpot 虚拟机回收器,首次出现在Open JDK12中,最初是由 RedHat公司开发,2014年贡献给 OpenJDK,或许因为它不是 Oracle公司自己开发的,所以,Shenandoah 目前只存在 OpenJDK 而不存在 OracleJDK商业版中。Shenandoah主要使用连接矩阵和转发指针的技术,连接矩阵替代 G1中的卡表。

Shenandoah工作流程分为 9个步骤:

  • Initial Marking(初始标记):和G1 一样,标记了从 GC Root开始直接可达的对象,Stop The World
  • Concurrent Marking(并发标记):和G1 一样,在整个堆上查找活动对象,标记全部可达对象。
  • Final Marking(最终标记):和G1 一样,
  • Concurrent Cleanup(并发清理):清理无存活对象的 Region
  • Concurrent Evacuation(并发回收):把存活的对象复制到空的 Region中,
  • Inital Update Reference(初始引用更新):修正并发回收阶段被复制对象的引用地址
  • Concurrent Update Reference(并发引用更新):引用更新操作
  • Final Update Reference(最终引用更新):修正存在于 GCRoots中的引用
  • Concurrent Cleanup(并发清理):回收空的 Region
2. Concurrent Marking(并发标记):和G1 一样,在整个堆上查找活动对象,标记全部可达对象。

Shenandoah 收集器大致的工作流程如下图(图片来自 OpenJDK官方):

九款常见的 JVM 垃圾回收器

在启动 Java进程时,可以通过设置XX:+UseShenandoahGC参数,显示使用 Shenandoah回收器。

注意,如果使用的是Sun/OracleJDK,将无法使用该回收器。

9.ZGC 

ZGC 是 Oracle官方研发并从 JDK11中引入,它是一款采用染色指针和读屏障技术的回收器,ZGC 和 G1一样,堆空间被划分成多个 Region,不同的是,ZGC的 Region 被官方称为Page,它可以动态创建和销毁,容量也可以动态调整。

ZGC的 Region分为三种:

  • 小型 Region:容量固定为 2MB,用于存放 < 256KB的对象;
  • 中型 Region:容量固定为 32MB,用于存放 >= 256KB且 < 4MB的对象;
  • 大型 Region:容量为 2^n MB,存放 >= 4MB 的对象,而且每个大型Region 中只存放一个大对象。由于大对象移动代价过大,所以该对象不会被重分配。

ZGC 工作流程分为 4个步骤:

  • Concurrent Mark(并发标记):和G1 一样,标记了从 GC Root开始直接可达的对象
  • Concurrent Prepare for Relocate(并发预备重分配)
  • Concurrent for Relocate(并发重分配)
  • Concurrent Remap(并发重映射)

ZGC 收集器大致的工作流程如下图:

九款常见的 JVM 垃圾回收器

ZGC垃圾回收过程几乎全部是并发,实际 Stop The World(STW)停顿时间极短,不到10ms。这得益于其采用的着色指针和读屏障技术。

在启动 Java进程时,可以通过设置XX:+UseZGC参数,显示使用 ZGC回收器。

到此,9款垃圾收集器就介绍完毕,如果你对垃圾回收器很感兴趣,推荐阅读周志明博士的《深入理解Java虚拟机》第三版,书中除了垃圾回收器, JVM其它相关的内容也都有详细地介绍,应该是国内很多 Java程序员学习 JVM的必备书籍。

因为篇幅有限,本文只是简单地分析了 HotSpot虚拟机常见的 9款垃圾回收器,并没有做原理上的分析,我会在接下来的文章中分别对 CMS,G1,ZGC,Shenandoah 4款垃圾收集器做详细的讲解,链接:JVM专栏 。最后用一张图表对 9款回收器做一个对比:

九款常见的 JVM 垃圾回收器


原文地址:https://mp.weixin.qq.com/s?__biz=MzIwNDAyOTI2Nw==&mid=2247491611&idx=1&sn=e3ea710a6e0bad4035254f731847b8fc

延伸 · 阅读

精彩推荐