不同场景可以使用不同的垃圾收集器来进行GC,不同的垃圾收集器有不同的特点,有的单线程执行适合单核、有的多线程并发执行、有的追求高吞吐量、有的追求低延迟...
在学习垃圾收集器前需要学习一定的前置知识如JVM运行时数据区、垃圾回收算法等,需要的同学可以查看该专栏下以前的文章,如
垃圾收集器的内容细节都比较多,文章将会分为上、中、下三篇
在上篇中主要介绍垃圾回收器的分类、性能指标以及串行与并行的垃圾收集器
在中篇中主要介绍并发的垃圾收集器以及并发执行带来的问题以及解决方案
在下篇中主要介绍低延迟的垃圾收集器
GC分类与性能指标
垃圾回收器分类
根据GC线程数进行分类,可以分为单GC线程串行和多GC线程并行的垃圾回收器
单线程串行顾名思义就是单线程执行GC,多线程并行就是多个线程同时执行GC(需要多核)
根据GC工作模式进行分类,可以分为同一时刻GC线程独占式和用户、GC线程并发的垃圾回收器
GC线程独占式是GC线程执行时用户线程需要停顿,而用户、GC线程并发式就是用户、GC线程并发执行
根据处理内存碎片进行分类,可以分为压缩式(无碎片内存)和非压缩式的垃圾回收器
根据处理内存区间进行分类,可以分为新生代、老年代的垃圾回收器
性能指标
在介绍垃圾回收器前,需要了解两个性能指标:吞吐量和延迟
在程序运行时,由于GC的存在,在进行GC时需要额外的开销,我们希望垃圾回收器能够有高吞吐量,尽早的完成GC,将运行时间留给用户线程去处理我们的程序
但因为种种原因可能导致GC的时间过长,这样就会延迟用户线程的执行,我们总是希望这种延迟是低的
GC的目标尽量追求高吞吐量和低延迟
高吞吐量表示GC处理的快,低延迟在交互程序中能给用户带来好的响应
但是高吞吐量和低延迟是冲突的
以高吞吐量为优先,就要减少GC频率,这样会导致GC需要更长的时间,从而导致延迟升高
以低延迟为优先,为了降低每次GC暂停更短的时间,只能增大GC频率,这样导致吞吐量降低
现在GC的目标是在高吞吐量优先的情况下尽量降低延迟;在低延迟优先的情况下尽量增大吞吐量
垃圾收集器
以GC线程运行状态来分类,经典的垃圾收集器分为串行、并行、并发垃圾收集器,现在还有两款低延迟垃圾收集器
串行垃圾收集器: Serial
、Serial Old
并行垃圾收集器: ParNew
、Parallel Scavenge
, Parallel Old
并发垃圾收集器: G1
、CMS
低延迟垃圾收集器: ZGC
、 Shenandoah
垃圾收集器可能只处理年轻代(新生代)或老年代,也可能对内存区域都进行处理
因为垃圾收集器可能只处理部分空间,因此要做到Full GC时,需要搭配其他垃圾收集器一起进行GC
比如Serial GC与Serial Old GC(图中黑线)
图中位于白色部分是处理年轻代的垃圾收集器,位于灰色部分是处理老年代的垃圾收集器,其中G1都会处理
垃圾收集器之间会进行搭配使用,但在高版本中可能移除这种搭配关系,也可能移除垃圾收集器
串行垃圾收集器
串行垃圾收集器主要有两种,分别处理年轻代与老年代,它们互相搭配使用
Serial收集器使用复制算法处理年轻代
Serial Old收集器使用标记-整理算法处理老年代
(新生代)Serial收集器 + (老年代)Serial Old 收集器 运行图
串行收集器(单线程),简单高效(在单线程中)、内存开销最小
收集过程中,必须暂停其他所有用户线程,直到它收集结束
默认Client模式的收集器,适合单核CPU 不适合交互式
JVM参数设置
-XX:+UseSerialGC
:新生代使用Serial GC 老年代使用 Serial Old GC
并行垃圾收集器
ParNew收集器
ParNew是Serial的并行版本,使用复制算法处理新生代
(新生代)ParNew收集器 + (老年代)Serial Old收集器 运行图
在单核情况下,Serial会比ParNew高效;在多核情况下,ParNew吞吐量会更高
年轻代使用ParNew时,老年代只能使用串行的Serial Old
JVM参数设置
-XX:+UseParNewGC
新生代使用ParNew
-XX:ParallelGCThreads=线程数
并行执行的GC线程数量
Parallel Scavenge收集器 和 Parallel Old收集器
Parallel Scavenge 是吞吐量优先的并行收集器,使用复制算法处理新生代
Parallel Old 使用标记-整理算法处理老年代
Parallel Scavenge收集器 + Parallel Old收集器运行图
与ParNew的不同:精确控制吞吐量,自适应调节策略
吞吐量越高说明最高效率利用处理器资源完成程序
参数设置
-XX:UseParallelGC
或-XX:UseParallelOldGC
互相激活
- 新生代使用ParallelGC 老年代使用Parallel Old GC
-XX:MaxGCPauseMillis
- 最大垃圾收集停顿时间
-XX:GCTimeRatio
- 控制GC时间
-XX:GCTimeRatio=99
时 GC时间占比 = 1 / (1 + 99) = 1%
-XX:+UseAdaptiveSizePolicy
- 自适应调节策略 默认开启
- 开启时JVM会根据系统运行情况动态调整
-XX:MaxGCPauseMillis
和-XX:GCTimeRatio
参数来设置最合适的停顿时间和GC时间
吞吐量优先垃圾收集器是JDK8默认使用的垃圾收集器
总结
本篇文章作为垃圾收集器系列文章的上篇,主要介绍从各个方面对垃圾收集器的分类、GC性能指标、串行垃圾收集器、并行垃圾收集器等
垃圾收集器可以划分为串行、并行、并发垃圾收集器,其中串行表示单GC线程独自执行、并行表示多GC线程同时刻执行、并发表示GC、用户线程并发执行
发生GC时需要考虑到的性能指标是高吞吐量(GC执行效率高)、低延迟(GC时的停顿时间尽量低),这两个指标往往不能都满足,不同的垃圾收集器有不同特点适合在不同场景下发挥作用
串行垃圾收集器Serial使用复制算法回收年轻代,搭配Serial Old使用标记-整理算法回收老年代,适合在单核、延迟不敏感的场景下使用,Client模式下的默认垃圾收集器
并行垃圾收集器ParNew可以看成Serial的并行版本,使用复制算法多GC线程并行回收年轻代,老年代使用Serial Old单GC线程回收老年代
吞吐量优先垃圾收集器Parallel Scavenge使用复制算法多GC线程并行回收年轻代,搭配Parallel Old使用标记-整理算法多GC线程并行回收老年代,提供最大停顿时间、GC时间占比、自适应调节等参数来让用户自定义使用,Server模式下默认垃圾收集器
并发垃圾收集器以及用户、GC线程并发执行带来的问题与解决方案将在垃圾收集器系列的中篇介绍
低延迟垃圾收集器将在垃圾收集器系列的下篇中介绍
最后
- 参考资料
- 《深入理解Java虚拟机》
本篇文章将被收入JVM专栏,觉得不错感兴趣的同学可以收藏专栏哟~
觉得菜菜写的不错,可以点赞、关注支持哟~
有什么问题可以在评论区交流喔~