JVM面试问题系列:7种JVM垃圾收集器特点,优劣势、及使用场景!

2023-11-01

一、常见垃圾收集器

现在常见的垃圾收集器有如下几种:

新生代收集器:

  • Serial
  • ParNew
  • Parallel Scavenge

老年代收集器:

  • Serial Old
  • CMS
  • Parallel Old

堆内存垃圾收集器:G1

每种垃圾收集器之间有连线,表示他们可以搭配使用。

二、新生代垃圾收集器

(1)Serial 收集器

Serial 是一款用于新生代的单线程收集器,采用复制算法进行垃圾收集。Serial 进行垃圾收集时,不仅只用一条线程执行垃圾收集工作,它在收集的同时,所有的用户线程必须暂停(Stop The World)。

就比如妈妈在家打扫卫生的时候,肯定不会边打扫边让儿子往地上乱扔纸屑,否则一边制造垃圾,一遍清理垃圾,这活啥时候也干不完。

如下是 Serial 收集器和 Serial Old 收集器结合进行垃圾收集的示意图,当用户线程都执行到安全点时,所有线程暂停执行,Serial 收集器以单线程,采用复制算法进行垃圾收集工作,收集完之后,用户线程继续开始执行。

适用场景:Client 模式(桌面应用);单核服务器。

可以用 -XX:+UserSerialGC 来选择 Serial 作为新生代收集器。

(2)ParNew 收集器

ParNew 就是一个 Serial 的多线程版本,其它与Serial并无区别。ParNew 在单核 CPU 环境并不会比 Serial 收集器达到更好的效果,它默认开启的收集线程数和 CPU 数量一致,可以通过 -XX:ParallelGCThreads 来设置垃圾收集的线程数。

如下是 ParNew 收集器和 Serial Old 收集器结合进行垃圾收集的示意图,当用户线程都执行到安全点时,所有线程暂停执行,ParNew 收集器以多线程,采用复制算法进行垃圾收集工作,收集完之后,用户线程继续开始执行。

适用场景:多核服务器;与 CMS 收集器搭配使用。当使用 -XX:+UserConcMarkSweepGC 来选择 CMS 作为老年代收集器时,新生代收集器默认就是 ParNew,也可以用 -XX:+UseParNewGC 来指定使用 ParNew 作为新生代收集器。

(3)Parallel Scavenge 收集器

Parallel Scavenge 也是一款用于新生代的多线程收集器,与 ParNew 的不同之处是ParNew 的目标是尽可能缩短垃圾收集时用户线程的停顿时间,Parallel Scavenge 的目标是达到一个可控制的吞吐量。

吞吐量就是 CPU 执行用户线程的的时间与 CPU 执行总时间的比值【吞吐量 = 运行用户代代码时间/(运行用户代码时间+垃圾收集时间)】,比如虚拟机一共运行了 100 分钟,其中垃圾收集花费了 1 分钟,那吞吐量就是 99% 。比如下面两个场景,垃圾收集器每 100 秒收集一次,每次停顿 10 秒,和垃圾收集器每 50 秒收集一次,每次停顿时间 7 秒,虽然后者每次停顿时间变短了,但是总体吞吐量变低了,CPU 总体利用率变低了。

可以通过 -XX:MaxGCPauseMillis 来设置收集器尽可能在多长时间内完成内存回收,可以通过 -XX:GCTimeRatio 来精确控制吞吐量。

如下是 Parallel 收集器和 Parallel Old 收集器结合进行垃圾收集的示意图,在新生代,当用户线程都执行到安全点时,所有线程暂停执行,ParNew 收集器以多线程,采用复制算法进行垃圾收集工作,收集完之后,用户线程继续开始执行;在老年代,当用户线程都执行到安全点时,所有线程暂停执行,Parallel Old 收集器以多线程,采用标记整理算法进行垃圾收集工作。

适用场景:注重吞吐量,高效利用 CPU,需要高效运算且不需要太多交互。

可以使用 -XX:+UseParallelGC 来选择 Parallel Scavenge 作为新生代收集器,jdk7、jdk8 默认使用 Parallel Scavenge 作为新生代收集器。

三、老年代垃圾收集器

(1)Serial Old 收集器

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

如下图是 Serial 收集器和 Serial Old 收集器结合进行垃圾收集的示意图:

适用场景:Client 模式(桌面应用);单核服务器;与 Parallel Scavenge 收集器搭配;作为 CMS 收集器的后备预案。

(2)CMS(Concurrent Mark Sweep) 收集器

CMS 收集器是一种以最短回收停顿时间为目标的收集器,以 “ 最短用户线程停顿时间 ” 著称。整个垃圾收集过程分为 4 个步骤:

① 初始标记:标记一下 GC Roots 能直接关联到的对象,速度较快。

② 并发标记:进行 GC Roots Tracing,标记出全部的垃圾对象,耗时较长。

③ 重新标记:修正并发标记阶段引用户程序继续运行而导致变化的对象的标记记录,耗时较短。

④ 并发清除:用标记-清除算法清除垃圾对象,耗时较长。

整个过程耗时最长的并发标记和并发清除都是和用户线程一起工作,所以从总体上来说,CMS 收集器垃圾收集可以看做是和用户线程并发执行的。

CMS 收集器也存在一些缺点:

对 CPU 资源敏感:默认分配的垃圾收集线程数为(CPU 数+3)/4,随着 CPU 数量下降,占用 CPU 资源越多,吞吐量越小

无法处理浮动垃圾:在并发清理阶段,由于用户线程还在运行,还会不断产生新的垃圾,CMS 收集器无法在当次收集中清除这部分垃圾。同时由于在垃圾收集阶段用户线程也在并发执行,CMS 收集器不能像其他收集器那样等老年代被填满时再进行收集,需要预留一部分空间提供用户线程运行使用。当 CMS 运行时,预留的内存空间无法满足用户线程的需要,就会出现 “ Concurrent Mode Failure ”的错误,这时将会启动后备预案,临时用 Serial Old 来重新进行老年代的垃圾收集。

因为 CMS 是基于标记-清除算法,所以垃圾回收后会产生空间碎片,可以通过 -XX:UserCMSCompactAtFullCollection 开启碎片整理(默认开启),在 CMS 进行 Full GC 之前,会进行内存碎片的整理。还可以用 -XX:CMSFullGCsBeforeCompaction 设置执行多少次不压缩(不进行碎片整理)的 Full GC 之后,跟着来一次带压缩(碎片整理)的 Full GC。

适用场景:重视服务器响应速度,要求系统停顿时间最短。可以使用 -XX:+UserConMarkSweepGC 来选择 CMS 作为老年代收集器。

(3)Parallel Old 收集器

Parallel Old 收集器是 Parallel Scavenge 的老年代版本,是一个多线程收集器,采用标记-整理算法。可以与 Parallel Scavenge 收集器搭配,可以充分利用多核 CPU 的计算能力。

适用场景:与Parallel Scavenge 收集器搭配使用;注重吞吐量。jdk7、jdk8 默认使用该收集器作为老年代收集器,使用 -XX:+UseParallelOldGC 来指定使用 Paralle Old 收集器。

四、新生代和老年代垃圾收集器

G1 收集器

G1 收集器是 jdk1.7 才正式引用的商用收集器,现在已经成为 jdk9 默认的收集器。前面几款收集器收集的范围都是新生代或者老年代,G1 进行垃圾收集的范围是整个堆内存,它采用 “ 化整为零 ” 的思路,把整个堆内存划分为多个大小相等的独立区域(Region),在 G1 收集器中还保留着新生代和老年代的概念,它们分别都是一部分 Region,如下图:

每一个方块就是一个区域,每个区域可能是 Eden、Survivor、老年代,每种区域的数量也不一定。JVM 启动时会自动设置每个区域的大小(1M ~ 32M,必须是 2 的次幂),最多可以设置 2048 个区域(即支持的最大堆内存为 32M*2048 = 64G),假如设置 -Xmx8g -Xms8g,则每个区域大小为 8g/2048=4M。

为了在 GC Roots Tracing 的时候避免扫描全堆,在每个 Region 中,都有一个 Remembered Set 来实时记录该区域内的引用类型数据与其他区域数据的引用关系(在前面的几款分代收集中,新生代、老年代中也有一个 Remembered Set 来实时记录与其他区域的引用关系),在标记时直接参考这些引用关系就可以知道这些对象是否应该被清除,而不用扫描全堆的数据。

G1 收集器可以 “ 建立可预测的停顿时间模型 ”,它维护了一个列表用于记录每个 Region 回收的价值大小(回收后获得的空间大小以及回收所需时间的经验值),这样可以保证 G1 收集器在有限的时间内可以获得最大的回收效率。

如下图所示,G1 收集器收集器收集过程有初始标记、并发标记、最终标记、筛选回收,和 CMS 收集器前几步的收集过程很相似:

① 初始标记:标记出 GC Roots 直接关联的对象,这个阶段速度较快,需要停止用户线程,单线程执行。

② 并发标记:从 GC Root 开始对堆中的对象进行可达新分析,找出存活对象,这个阶段耗时较长,但可以和用户线程并发执行。

③ 最终标记:修正在并发标记阶段引用户程序执行而产生变动的标记记录。

④ 筛选回收:筛选回收阶段会对各个 Region 的回收价值和成本进行排序,根据用户所期望的 GC 停顿时间来指定回收计划(用最少的时间来回收包含垃圾最多的区域,这就是 Garbage First 的由来——第一时间清理垃圾最多的区块),这里为了提高回收效率,并没有采用和用户线程并发执行的方式,而是停顿用户线程。

适用场景:要求尽可能可控 GC 停顿时间;内存占用较大的应用。可以用 -XX:+UseG1GC 使用 G1 收集器,jdk9 默认使用 G1 收集器。

五、JVM垃圾收集器总结

本文主要介绍了JVM中的垃圾回收器,主要包括串行回收器、并行回收器以及CMS回收器、G1回收器。他们各自都有优缺点,通常来说你需要根据你的业务,进行基于垃圾回收器的性能测试,然后再做选择。下面给出配置回收器时,经常使用的参数:

-XX:+UseSerialGC:在新生代和老年代使用串行收集器

-XX:+UseParNewGC:在新生代使用并行收集器

-XX:+UseParallelGC :新生代使用并行回收收集器,更加关注吞吐量

-XX:+UseParallelOldGC:老年代使用并行回收收集器

-XX:ParallelGCThreads:设置用于垃圾回收的线程数

-XX:+UseConcMarkSweepGC:新生代使用并行收集器,老年代使用CMS+串行收集器

-XX:ParallelCMSThreads:设定CMS的线程数量

-XX:+UseG1GC:启用G1垃圾回收器

JVM系列:

深入详解JVM 内存区域及内存溢出分析

JVM的判断对象是否已死和四种垃圾回收算法

JVM 配置常用参数和常用 GC 调优策略

7种JVM垃圾收集器特点,优劣势、及使用场景!

最后

后续会持续更新性能优化专题知识,写的不好的地方也希望大牛能指点一下,大家觉得不错可以点个赞在关注下,以后还会分享更多文章!


本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

JVM面试问题系列:7种JVM垃圾收集器特点,优劣势、及使用场景! 的相关文章

随机推荐

  • 35. 实战:Python实现视频去水印(文末源码)

    目录 前言 目的 思路 代码实现 1 请求URL 查看源代码 2 源代码中没有就去抓包工具 3 拿到视频源链接 继续检索来源 4 拿到数据和链接 二进制写入到本地 完整源码 运行效果 总结 前言 我们在刷某短视频平台时 有些视频我们想保存到
  • 系统安装部署系列教程(六):封装系统

    终于到了本系列的最核心一篇教程了 在这篇教程里我们来看看如何按需来封装系统 封装系统有很多作用 硬件厂商需要将自己的特性软件和驱动程序预装到系统中 企业用户需要集成KMS激活服务器 装机人员需要预装用户的常用软件 所有这些功能 都可以通过封
  • yearning

    Yearning 开发模式 手动部署 如有侵权 请联系我删除 环境准备 MySQL https www cnblogs com xinjing jingxin p 8025805 html Yearning git clone https
  • 【Matlab基础】一些常用函数收集

    stem函数 1 用法 stem Y 将数据序列Y从x轴到数据值按照茎状形式画出 以圆圈终止 如果Y是一个矩阵 则将其每一列按照分隔方式画出 stem X Y 在X的指定点处画出数据序列Y stem filled 以实心的方式画出茎秆 st
  • yolov6 win10环境配置详细过程

    提示 文章写完后 目录可以自动生成 如何生成可参考右边的帮助文档 文章目录 前言 一 yolov6 下载 二 环境配置 三 测试环境 四 报错集合 前言 提示 这里可以添加本文要记录的大概内容 最近美团开源了yolov6 源码 准备体验下y
  • 韩国KT/LG/SK机房服务器比较

    众所周知 韩国就KT LG SK机房比较出名 那么三者之间有和区别呢 小编带大家分析一下 如有不对的地方还请多多指教 一 KT机房 KT机房采用中韩CN2专线与联通移动BGP线路 线路稳定不掉包 三网用户访问速度快而且速度和国内服务器没什么
  • 关于VAE中KL散度项的推导

    关于VAE中KL散度项的推导 最近在看 Variational AutoEncoder 其中论文 Auto Encoding Variational Bayes 中的Eq 10 怎么也推不出来 看了一下Appendix B 只给出了KL散度
  • 开发自己的脚手架(Rollup+Typescript)-(02)-(中间件模式)

    对于A gt b gt c这一类的流程事件 可以采用分解这些事件 当需要用到这些事件操作时 我们将操作插入到核心事件完成所需要的不同步骤中 实现一个流程处理函数 src core ware ts 中间件方法类型 export type Mi
  • ES6 let 与 const 命令 以及箭头函数初步学习

    ES6 let 与 const 命令 以及箭头函数初步学习 ES6 let 与 const 命令 以及箭头函数初步学习 let 与 const let 块级作用于 const 本质 ES6 声明变量的六种方法 ES6箭头函数 箭头函数与普通
  • CRM常用功能代码

    文章目录 前言 学习任务 一 常用框架 BS入口 方法体 二 常用功能 1 动态Pick 2 简单查询 3 通过值列表Code获取值 获取系统参数 模板 内置参数 4 开关管理员模式 遇到问题及其解决方案 心得总结 前言 学习情况总结 学习
  • ARMv8之arm64架构汇编知识

    1 寄存器 1 1 通用寄存器 31 个R0 R30 每一个寄存器能够存取一个64位大小的数 当使用 x0 x30访问时 是一个 64位的数 当使用 w0 w30访问时 是一个 32 位的数 访问的是寄存器的低32位 如下图所示 1 2 向
  • 线性表的顺序存储实现(数组)

    数据对象集 线性表是个元素构成的有序序列 操作集 线性表 整数i表示位置 元素 线性表主要操作如下 List MakeEmpty 初始化一个空线性表 ElementType FinKth int K List PtrL 根据位序K 返回相应
  • matlab迭代算法实例_【优化求解】基于NSGA2的求解多目标柔性车间调度算法

    柔性作业车间调度问题 FJSP 是经典作业车间调度问题的重要扩展 其中每个操作可以在多台机器上处理 反之亦然 结合实际生产过程中加工时间 机器负载 运行成本等情况 建立了多目标调度模型 针对NSGA2算法收敛性不足的缺陷 引入免疫平衡原理改
  • 比特位计数

    题目链接 比特位计数 题目描述 注意点 对于 0 lt i lt n 中的每个 i 计算其二进制表示中 1 的个数 解答思路 采用动态规划的思想 任意一个数字的1的个数可以由前面数字1的个数推出 除2的n次方的数字外 所以任意一个数字有两种
  • 解决:AttributeError: ‘generator‘ object has no attribute ‘next‘

    报错信息 AttributeError generator object has no attribute next 解决 经过查询发现是python版本之间的问题 把原来的next改为 next 注意是两个下划线
  • vscode 单行注释和多行注释

    单行注释 ctrl 多行注释 alt shift A 代码快速格式化 alt shift F 函数注释 后回车即可
  • 通过Python解决分布式爬虫中的代理难题

    在当今信息爆炸的时代 爬虫技术成为了获取互联网数据的重要手段 然而 随着网站对爬虫的限制越来越严格 分布式爬虫面临的代理难题也日益突出 本文将为你介绍一些实用的Python解决方案 帮助你轻松应对分布式爬虫中的代理问题 让你事半功倍 1 使
  • 利用github.io(githubPages)免费托管个人静态网站/个人博客

    我们的个人博客或者静态网站可以托管到github就能通过github域名访问 免费 省事 当然也可以使用自定义的域名解析 花钱 高大上 git仓库配置 我采用的是自己编写一个html文件 githubPages搭建 首先需要在GitHub上
  • 强化学习算法 Sarsa 解迷宫游戏,代码逐条详解

    本文内容源自百度强化学习 7 日入门课程学习整理 感谢百度 PARL 团队李科浇老师的课程讲解 强化学习算法 Sarsa 解迷宫游戏 文章目录 一 安装依赖库 二 导入依赖库 三 智能体 Agent 的算法 Sarsa 四 训练和测试语句
  • JVM面试问题系列:7种JVM垃圾收集器特点,优劣势、及使用场景!

    一 常见垃圾收集器 现在常见的垃圾收集器有如下几种 新生代收集器 Serial ParNew Parallel Scavenge 老年代收集器 Serial Old CMS Parallel Old 堆内存垃圾收集器 G1 每种垃圾收集器之