在前面,我们已经了解了JVM的分代收集,知道JVM垃圾收集在新生代主要采用标记-复制算法,在老年代主要采用标记-清除标记-整理算法。接下来,我们看一看JDK默认虚拟机HotSpot的一些垃圾收集器的实现。

1、常见垃圾回收器

首先来看一下JDK 11之前全部可用的垃圾收集器。

图中列出了七种垃圾收集器,连线表示可以配合使用,所在区域表示它是属于新生代收集器或是老年代收集器。

这里还标出了垃圾收集器采用的收集算法,G1收集器比较特殊,整体采用标记-整理算法,局部采用标记-复制算法,后面再细讲。

1.1、Serial收集器

Serial收集器是最基础、历史最悠久的收集器。

如同它的名字(串行),它是一个单线程工作的收集器,使用一个处理器或一条收集线程去完成垃圾收集工作。并且进行垃圾收集时,必须暂停其他所有工作线程,直到垃圾收集结束——这就是所谓的“Stop The World”。

Serial/Serial Old收集器的运行过程如图:

1.2、ParNew收集器

ParNew收集器实质上是Serial收集器的多线程并行版本,使用多条线程进行垃圾收集。

ParNew收集器的工作过程如图所示:

这里值得一提的是Par是Parallel(并行)的缩写,但需要注意的是,这个并行(Parallel)仅仅是描述同一时间多条GC线程协同工作,而不是GC线程和用户线程同时运行。ParNew垃圾收集也是需要Stop The World的。

1.3、Parallel Scavenge收集器

Parallel Scavenge收集器是一款新生代收集器,基于标记-复制算法实现,也能够并行收集。和ParNew有些类似,但Parallel Scavenge主要关注的是垃圾收集的吞吐量。

所谓吞吐量指的是运行用户代码的时间与处理器总消耗时间的比值。这个比例越高,证明垃圾收集占整个程序运行的比例越小。

Parallel Scavenge收集器提供了两个参数用于精确控制吞吐量:

  • -XX:MaxGCPauseMillis,最大垃圾回收停顿时间。这个参数的原理是空间换时间,收集器会控制新生代的区域大小,从而尽可能保证回收少于这个最大停顿时间。简单的说就是回收的区域越小,那么耗费的时间也越小。

    所以这个参数并不是设置得越小越好。设太小的话,新生代空间会太小,从而更频繁的触发GC。

  • -XX:GCTimeRatio,垃圾收集时间与总时间占比。这个是吞吐量的倒数,原理和MaxGCPauseMillis相同。

由于与吞吐量关系密切,Parallel Scavenge收集器也经常被称作“吞吐量优先收集器”。

1.4、Serial Old收集器

Serial Old是Serial收集器的老年代版本,它同样是一个单线程收集器,使用标记-整理算法。

Serial Old收集器的工作过程如图:

1.5、Parallel Old收集器

Parallel Old是Parallel Scavenge收集器的老年代版本,支持多线程并发收集,基于标记-整理算法实现。

1.6、CMS收集器

CMS(Concurrent Mark Sweep)收集器是一种以获取最短回收停顿时间为目标的收集器,同样是老年代的收集齐,采用标记-清除算法。

CMS收集齐的垃圾收集分为四步:

  • 初始标记(CMS initial mark):单线程运行,需要Stop The World,标记GC Roots能直达的对象。
  • 并发标记((CMS concurrent mark):无停顿,和用户线程同时运行,从GC Roots直达对象开始遍历整个对象图。
  • 重新标记(CMS remark):多线程运行,需要Stop The World,标记并发标记阶段产生对象。
  • 并发清除(CMS concurrent sweep):无停顿,和用户线程同时运行,清理掉标记阶段标记的死亡的对象。

涉及到了多次标记的过程,这里插入一点三色抽象的知识。三色抽象用来描述对象在垃圾收集过程中的状态。

通常白色代表对象未被扫描到,灰色表示对象被扫描到但未被处理,黑色表示对象及其后代已被处理。在CMS的标记和清除过程中就用到了这种抽象,详细的可以查看参考【5】。

Concurrent Mark Sweep收集器运行示意图如下:

优点:CMS最主要的优点在名字上已经体现出来——并发收集、低停顿。

缺点:CMS同样有三个明显的缺点。

  • Mark Sweep算法会导致内存碎片比较多

  • CMS的并发能力比较依赖于CPU资源,并发回收时垃圾收集线程可能会抢占用户线程的资源,导致用户程序性能下降。

  • 并发清除阶段,用户线程依然在运行,会产生所谓的理“浮动垃圾”(Floating Garbage),本次垃圾收集无法处理浮动垃圾,必须到下一次垃圾收集才能处理。如果浮动垃圾太多,会触发新的垃圾回收,导致性能降低。

1.7、Garbage First收集器

Garbage First(简称G1)收集器是垃圾收集器的一个颠覆性的产物,它开创了局部收集的设计思路和基于Region的内存布局形式。

虽然G1也仍是遵循分代收集理论设计的,但其堆内存的布局与其他收集器有非常明显的差异。以前的收集器分代是划分新生代、老年代、持久代等。

G1把连续的Java堆划分为多个大小相等的独立区域(Region),每一个Region都可以根据需要,扮演新生代的Eden空间、Survivor空间,或者老年代空间。收集器能够对扮演不同角色的Region采用不同的策略去处理。

这样就避免了收集整个堆,而是按照若干个Region集进行收集,同时维护一个优先级列表,跟踪各个Region回收的“价值,优先收集价值高的Region。

G1收集器的运行过程大致可划分为以下四个步骤:

  • 初始标记(initial mark),标记了从GC Root开始直接关联可达的对象。STW(Stop the World)执行。

  • 并发标记(concurrent marking),和用户线程并发执行,从GC Root开始对堆中对象进行可达性分析,递归扫描整个堆里的对象图,找出要回收的对象、

  • 最终标记(Remark),STW,标记再并发标记过程中产生的垃圾。

  • 筛选回收(Live Data Counting And Evacuation),制定回收计划,选择多个Region 构成回收集,把回收集中Region的存活对象复制到空的Region中,再清理掉整个旧 Region的全部空间。需要STW。

相比CMS,G1的优点有很多,可以指定最大停顿时间、分Region的内存布局、按收益动态确定回收集。

只从内存的角度来看,与CMS的“标记-清除”算法不同,G1从整体来看是基于“标记-整理”算法实现的收集器,但从局部(两个Region 之间)上看又是基于“标记-复制”算法实现,无论如何,这两种算法都意味着G1运作期间不会产生内存空间碎片,垃圾收集完成之后能提供规整的可用内存。

2、前沿垃圾回收器

2.1、ZGC收集器

在JDK 11当中,加入了实验性质的ZGC。它的回收耗时平均不到2毫秒。它是一款低停顿高并发的收集器。

与CMS中的ParNew和G1类似,ZGC也采用标记-复制算法,不过ZGC对该算法做了重大改进:ZGC在标记、转移和重定位阶段几乎都是并发的,这是ZGC实现停顿时间小于10ms目标的最关键原因。

ZGC虽然在JDK 11还处于实验阶段,但由于算法与思想是一个非常大的提升,未来前景相信还是很广阔的。

3、垃圾收集器选择

3.1、收集器选择权衡

垃圾收集器的选择需要权衡的点还是比较多的——例如运行应用的基础设施如何?使用JDK的发行商是什么?等等……

这里简单地列一下上面提到的一些收集器的适用场景:

  • Serial :如果应用程序有一个很小的内存空间(大约100 MB)亦或它在没有停顿时间要求的单线程处理器上运行。
  • Parallel:如果优先考虑应用程序的峰值性能,并且没有时间要求要求,或者可以接受1秒或更长的停顿时间。
  • CMS/G1:如果响应时间比吞吐量优先级高,亦或垃圾收集暂停必须保持在大约1秒以内。
  • ZGC:如果响应时间是高优先级的,亦或堆空间比较大。

3.1、设置垃圾收集器

设置垃圾收集器(组合)的参数如下:

新生代 老年代 JVM 参数
Incremental Incremental -Xincgc
Serial Serial -XX:+UseSerialGC
Parallel Scavenge Serial -XX:+UseParallelGC -XX:-UseParallelOldGC
Parallel New Serial N/A
Serial Parallel Old N/A
Parallel Scavenge Parallel Old -XX:+UseParallelGC -XX:+UseParallelOldGC
Parallel New Parallel Old N/A
Serial CMS -XX:-UseParNewGC -XX:+UseConcMarkSweepGC
Parallel Scavenge CMS N/A
Parallel New CMS -XX:+UseParNewGC -XX:+UseConcMarkSweepGC
G1 -XX:+UseG1GC

参考:

【1】:周志朋编著《深入理解Java虚拟机:JVM高级特性与最佳实践》

【2】:《垃圾回收算法手册 自动内存管理的艺术》

【3】:Garbage Collection in Java – What is GC and How it Works in the JVM

【4】:Java Hotspot G1 GC的一些关键技术

【5】:GC Algorithms: Implementations

【6】:新一代垃圾回收器ZGC的探索与实践

【JVM进阶之路】七:垃圾收集器盘点的更多相关文章

  1. JVM性能优化系列-(2) 垃圾收集器与内存分配策略

    2. 垃圾收集器与内存分配策略 垃圾收集(Garbage Collection, GC)是JVM实现里非常重要的一环,JVM成熟的内存动态分配与回收技术使Java(当然还有其他运行在JVM上的语言,如 ...

  2. java虚拟机学习-JVM内存管理:深入垃圾收集器与内存分配策略(4)

    Java与C++之间有一堵由内存动态分配和垃圾收集技术所围成的高墙,墙外面的人想进去,墙里面的人却想出来. 概述: 说起垃圾收集(Garbage Collection,下文简称GC),大部分人都把这项 ...

  3. JVM学习笔记三:垃圾收集器与内存分配策略

    内存回收与分配重点关注的是堆内存和方法区内存(程序计数器占用小,虚拟机栈和本地方法栈随线程有相同的生命周期). 一.判断对象是否存活? 1. 引用计数算法 优势:实现简单,效率高. 致命缺陷:无法解决 ...

  4. 查看JVM使用的默认的垃圾收集器

    一.查看步骤 cmd执行命令: java -XX:+PrintCommandLineFlags -version 输出如下(举例): 针对上述的-XX:UseParallelGC,这边我们引用< ...

  5. jvm系列(三):GC算法 垃圾收集器

    原文出处:纯洁的微笑 这篇文件将给大家介绍GC都有哪几种算法,以及JVM都有那些垃圾回收器,它们的工作原理. 概述 垃圾收集 Garbage Collection 通常被称为"GC" ...

  6. Spark(八)JVM调优以及GC垃圾收集器

    一JVM结构 1 Java内存结构 JVM内存结构主要有三大块:堆内存.方法区和栈. 堆内存是JVM中最大的一块由年轻代和老年代组成,而年轻代内存又被分成三部分,Eden空间.From Survivo ...

  7. JVM垃圾回收算法 及 垃圾收集器

    摘自<深入理解Java虚拟机> 一.什么是: GC算法是 方法论,那么垃圾收集器就是具体的 实现. 二.四种 垃圾回收算法 1.标记-清除算法:最基础的收集算法:不足有两点:1标记和清除两 ...

  8. JVM 的GC算法和垃圾收集器

    1.标记清除算法 黑色部分代表可回收对象,灰色部分代表存活对象,绿色部分代表未使用的.最基础的收集算法就是标记清除算法如同他名字一样,算法分为"标记"和"清除" ...

  9. 【JVM学习笔记二】垃圾收集器与内存分配策略

    1. 概述 1) GC的历史比Java久远 2) GC需要完成的三件事: | 哪些内存需要回收 | 什么时候回收 | 如何回收 3) Java内存运行时区域各个部分: | Java虚拟机栈.计数器.本 ...

随机推荐

  1. Linux command find All In One

    Linux command find All In One $ find -h # find: illegal option -- h # usage: # find [-H | -L | -P] [ ...

  2. TypeScript keyof typeof All In one

    TypeScript keyof typeof All In one keyof typeof refs https://www.typescriptlang.org/docs/handbook/re ...

  3. PDF transform to PPT online & free

    PDF transform to PPT online & free > Speaker Deck Share Presentationswithout the Mess Speaker ...

  4. css text-align-last & text-align

    css text-align-last & text-align css https://caniuse.com/mdn-css_properties_text-align-last http ...

  5. git whoami

    git whoami $ git config --list $ git config --global --list # quit $ q $ git config user.name xgqfrm ...

  6. frontends tools

    frontends tools figma free online UI 可视化埋点 https://www.figma.com/files/recent cypress testing $ npm ...

  7. js destructuring assignment bug

    js destructuring assignment bug https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Op ...

  8. xcode upgrade & git bug

    xcode upgrade & git bug ➜ op-static git checkout feature/select-seat-system Agreeing to the Xcod ...

  9. qt char与code的相互转换

    QString str = "A"; QChar c = str.at(0); // int v_latin = c.toLatin1(); // 不能转中文 int v_lati ...

  10. 软件工程中的CI&CD

    wiki 在软件工程中,CI/CD或CICD通常是指持续集成以及持续交付或持续部署的组合实践 持续集成 在软件工程中,持续集成(CI)是每天将所有开发人员的工作副本合并到共享主线中的一种做法.[1] ...