垃圾回收器分类(学习笔记)
目录
GC分类
垃圾收集器没有在规范中进行过多规定,可以由不同厂商、不同版本的JVM来实现。
串行回收与并行回收
串行回收是指在同一时间段内只允许由一个CPU用于执行垃圾回收操作,此时工作线程暂停,直到垃圾回收工作结束。
- 在诸如单CPU处理器或者较小的引用内存的场合,串行回收器的性能可以超过并行回收器和并发回收器。所以,串行回收模式某人被应用在客户端的Client模式下的JVM中
- 在并发能力比较强的CPU上,并行回收器的停顿时间要短于串行回收器
并行回收可以使用多个CPU同时执行垃圾回收,因此提升了应用的吞吐量。
并发式与独占式
并发式垃圾回收器与应用线程交替工作,以尽可能减少应用程序的停顿。
独占式垃圾回收器一旦运行,就停止应用程序中的所有用户线程,直到垃圾回收工作结束。
- 串行回收与并行回收都是独占式垃圾回收
其他分类方式
碎片处理方式:压缩式垃圾回收器与非压缩式垃圾回收器
- 压缩式垃圾回收器会在回收完成后,对存活对象进行压缩整理,清除回收后的碎片
工作的内存区间:年轻代垃圾回收器和老年代垃圾回收器
GC的性能指标
- 吞吐量:运行用户代码的时间占总运行时间的比例
- 垃圾收集开销:吞吐量的补数,垃圾收集所用时间占总运行时间的比例
- 暂停时间:执行垃圾收集时,程序的工作线程被暂停的时间
- 收集频率:相对于应用程序的执行,收集操作发生的频率
- 内存占用:Java堆所占的内存大小
- 快速:一个对象从诞生到被回收所经历的时间
“吞吐量”、“暂停时间”、“内存占用”共同构成了一个“不可能三角”。一款优秀的收集器通常最多满足其中两项。
这三项里,暂停时间和吞吐量是重点被考虑的两项。
吞吐量
吞吐量用公式可以表示为:
运
行
用
户
代
码
的
时
间
运
行
用
户
代
码
的
时
间
+
垃
圾
回
收
的
时
间
\frac{运行用户代码的时间}{运行用户代码的时间+垃圾回收的时间}
运行用户代码的时间+垃圾回收的时间运行用户代码的时间
高吞吐量的应用程序由更长的时间基准,快速响应是不必考虑的。
暂停时间
暂停时间是只一个时间段内,应用程序线程暂停,让GC线程执行的时间。
暂停时间优先,意味着让单次STW的时间最短。
交互式的应用程序更关注低暂停时间(低延迟)。
吞吐量VS暂停时间
- 如果吞吐量优先,那么必然降低内存回收的执行频率,但是这样会导致GC需要更长的暂停时间来执行内存回收
- 如果低延迟优先,,那么为了降低每次执行内存回收的暂停时间,也只能频繁地执行内存回收,但这又引起了年轻代内存的缩减和导致程序吞吐量的下降。
在设计/使用GC算法时,必须明确自己的目标。
- 现有标准:在最大吞吐量优先的情况下,降低停顿时间。
- G1标准:在可控停顿时间的基础下,尽量提高吞吐量。
垃圾回收器的发展史
时间 | Java版本 | 垃圾回收器 | 特点 | HotSpot默认GC |
---|---|---|---|---|
1999年 | JDK1.3.1 | Serial GC | 串行,它是第一款Java GC | JDK1.3.1 |
ParNew | Serial GC的多线程版本 | |||
2006年2月 | JDK1.4.2 | Parallel GC | 并行GC | JDK6 |
Concurrent Mark Sweep GC | ||||
2012年 | JDK1.7u4 | G1 | JDK9 | |
2018年3月 | JDK10 | G1 | 实现并行性来改善最坏情况下的延迟 | |
2018年9月 | JDK11 | No-Op(无操作)回收器 | ||
ZGC(实验性) | 可伸缩的低延迟垃圾回收器 | |||
2019年3月 | JDK12 | 增强G1 | 自动返回未用堆内存给操作系统 | |
Shenandoah GC | 低停顿时间的GC | |||
2019年9月 | JDK13 | 增强ZGC(实验性) | 自动返回未用堆内存给操作系统 | |
2020年3月 | JDK14 | 增强ZGC(实验性) | 扩展ZGC在macOS和Windows上的应用 | |
删除CMS垃圾回收器 |
七种经典垃圾回收器
- 串行回收器:Serial、Serial Old
- 并行回收器:ParNew、Parallel Scavenge、Parallel Old
- 并发回收器:CMS、G1
垃圾回收器与垃圾分代的关系:
- G1是整堆收集器
垃圾回收器的组合关系(JDK14):
虚线+实线:JDK8之前(不含JDK8),垃圾回收器可以使用的组合方式。
- Serial Old GC是CMS的后备方案,当内存空间满时,CMS GC会切换为Serial Old GC。
红色虚线:这些组合方式在JDK8中被弃用(不推荐使用),在JDK9中被移除(不能使用)。
绿色虚线:在JDK14中被弃用。
青色边框:在JDK14中被移除。
为什么要有很多收集器?
因为Java的使用场景很多。针对不同的场景,提供不同的垃圾收集器,提高垃圾收集的性能。
我们选择的只是对具体应用最合适的收集器。
如何查看默认的垃圾回收器
- -XX:+PrintCommandLineFlags:查看命令行相关参数(包含垃圾回收器)
- 命令行指令:jinfo -flag 相关垃圾回收器参数 进程ID
具体的垃圾回收器学习
Serial与Serial Old垃圾回收器
ParNew垃圾回收器
Parallel与Parallel Old垃圾回收器
CMS垃圾回收器
G1垃圾回收器
ZGC等新世代GC
垃圾回收器的小结
垃圾收集器 | 分类 | 作用位置 | 使用算法 | 特点 | 使用场景 |
---|---|---|---|---|---|
Serial | 串行 | 新生代 | 复制算法 | 响应速度优先 | 单CPU环境下的client模式 |
Serial Old | 串行 | 老年代 | 标记-压缩算法 | 响应速度优先 | 单CPU环境下的client模式 |
ParNew | 并行 | 新生代 | 复制算法 | 响应速度优先 | 多CPU环境下的server模式,与CMS配合使用 |
Parallel | 并行 | 新生代 | 复制算法 | 吞吐量优先 | 后台运算而不需要太多交互场景 |
Parallel Old | 并行 | 老年代 | 标记-压缩算法 | 吞吐量优先 | 后台运算而不需要太多交互场景 |
CMS | 并发 | 老年代 | 标记-清除算法 | 响应速度优先 | 互联网或B/S业务 |
G1 | 并发、并行 | 新生代、老年代 | 标记-压缩算法、复制算法 | 响应速度优先 | 服务端应用 |
最小化地使用内存和并行开销,使用Serial GC。
最大化应用程序吞吐量,使用Parallel GC。
最小化GC的中断和停顿时间,使用CMS GC。
没有最好的收集器,更没有万能的收集器。
调优永远是针对特定场景、特定需求,不存在一劳永逸的收集器。