HotSpot共有7种垃圾收集器,3个新生代垃圾收集器,3个老年代垃圾收集器,以及G1,一共构成7种可供选择的垃圾收集器组合。
新生代与老年代垃圾收集器之间形成6种组合,每个新生代垃圾收集器都对应2种组合。
所有新生代垃圾收集器,都使用复制算法,都会发生stop-the-world。由于绝大多数对象的生命周期通常比较短,在新生代被回收的可能性很大,新生代的垃圾回收通常可以回收大部分对象,因此采用复制算法效率更高。
采用复制算法,GC时发生stop-the-world,使用单个GC线程。
“Serial” is a stop-the-world, copying collector which uses a single GC thread.
特点:
⠀Serial/Serial Old收集器协同工作运行示意图如下:
采用复制算法,GC时发生stop-the-world,使用多个GC线程。
ParNew 与 Parallel Scavenge的一个主要区别是,ParNew可以与CMS进行搭配使用。
“ParNew” is a stop-the-world, copying collector which uses multiple GC threads. It differs from “Parallel Scavenge” in that it has enhancements that make it usable with CMS. For example, “ParNew” does the synchronization needed so that it can run during the concurrent phases of CMS.
特点:
采用复制算法,GC时发生stop-the-world,使用多个GC线程。 吞吐量优先收集器,可控制最大垃圾收集停顿时间(-XX:MaxGCPauseMillis)与吞吐量大小(-XX:GCTimeRatio),支持GC自适应的调节策略(GC Ergonomics,对应参数-XX:+UseAdaptiveSizePolicy)。
“Parallel Scavenge” is a stop-the-world, copying collector which uses multiple GC threads.
特点:
ParNew和Parallel Scavenge基本没什么区别,都是年轻代的垃圾回收器,就是在Parallel Scavenge的基础上做了一些简单的增强使其能够较好的配合CMS的使用,ParNew是Parallel Scavenge的一个变种
ParNew响应时间优先,Parallel Scavenge吞吐量优先
吞吐量
吞吐量就是CPU用于运行用户代码的时间与CPU总消耗时间的比值,即吞吐量 = 运行用户代码时间 /(运行用户代码时间 + 垃圾收集时间)。
假设虚拟机总共运行了100分钟,其中垃圾收集花掉1分钟,那吞吐量就是99%。
通常来说,停顿时间越短(低延迟)就越适合需要与用户交互或需要保证服务响应质量的程序, 良好的响应速度能提升用户体验;
而高吞吐量则可以最高效率地利用处理器资源,尽快完成程序的运算任务, 主要适合在后台运算而不需要太多交互的分析任务。
除了CMS,其他的老年代垃圾收集器GC时都是stop-the-world,都会在清理垃圾之后进行压缩整理。
采用标记整理算法,GC时发生stop-the-world,使用单个GC线程。
“Serial Old” is a stop-the-world, mark-sweep-compact collector that uses a single GC thread.
特点:
⠀Serial/Serial Old收集器协同工作运行示意图如下:
采用标记整理算法,GC时发生stop-the-world,使用多个GC线程。
“Parallel Old” is a compacting collector that uses multiple GC threads.
特点:
整合和压缩算法
对内存进行整合和压缩是指在垃圾回收过程中对内存中的对象进行整理和重新排列,通过将存活对象向一端移动,以创建更大的连续内存空间,减少内存碎片并提高内存利用率的过程。这通常涉及将对象复制到新的内存空间,然后将原来的内存空间释放。这个过程通常发生在老年代的垃圾回收中。
⠀Parallel Scavenge/Parallel Old 收集器运行示意图如下:
CMS采用标记清理算法,是一个以低暂停时间为目标的垃圾收集器。GC时大部分时间并发执行,其中初始化标记和重新标记两个阶段仍然会发生stop-the-world,其余阶段都是并发执行。
“CMS” is a mostly concurrent, low-pause collector.
Java之CMS GC的7个阶段:https://mp.weixin.qq.com/s/vmnBlrM7pTtVuyQU-GTcPw
收集流程:
CMS整个过程的四个步骤如下,其中初始标记、 重新标记这两个步骤仍然需要“Stop The World”。
1. 初始标记-仅仅只是标记一下GC Roots能直接关联到的对象,速度很快
2. 并发标记-从GC Roots的直接关联对象开始遍历整个对象图的过程,这个过程耗时较长但是不需要停顿用户线程,可以与垃圾收集线程一起并发运行
3. 重新标记-为了修正并发标记期间,因用户程序继续运作而导致标记产生变动的那一部分对象的标记记录,这个阶段的停顿时间通常会比初始标记阶段稍长一些, 但也远比并发标记阶段的时间短
4. 并发清除-清理删除掉标记阶段判断的已经死亡的对象, 由于不需要移动存活对象, 所以这个阶段也是可以与用户线程同时并发的
Concurrent Mark Sweep 收集器运行示意图如下:
缺点:
关于CMS收集器浮动垃圾的说明:
由于在CMS的并发标记和并发清理阶段,用户线程是还在继续运行的,程序在运行自然就还会伴随有新的垃圾对象不断产生,但这一部分垃圾对象是出现在标记过程结束以后,CMS无法在当次收集中处理掉它们, 只好留待下一次垃圾收集时再清理掉。这一部分垃圾就称为“浮动垃圾”。
由于在垃圾收集阶段用户线程还需要持续运行, 那就还需要预留足够内存空间提供给用户线程使用, 因此CMS收集器不能像其他收集器那样等待到老年代几乎完全被填满了再进行收集,必须预留一部分空间供并发收集时的程序运作使用。
G1将整个堆划分为多个大小相等的独立区域(Region),保留新生代和老年代的分代概念(但两者不再是物理隔离的)。
从整体来看是基于标记整理算法,从局部(两个Region之间)来看是基于复制算法。因此,可以避免产生内存空间碎片,防止发生并发模式失败。
使用多个GC线程,每次优先回收价值最大的Region。
支持可预测的停顿时间模型,从而提高收集效率,降低stop-the-world的时间。
The Garbage First or G1 garbage collector is available in Java 7 and is designed to be the long term replacement for the CMS collector. The G1 collector is a parallel, concurrent, and incrementally compacting low-pause garbage collector that has quite a different layout from the other garbage collectors described previously.
特点:
G1 收集器的运作过程主要步骤如下:
⠀从上述阶段的描述可以看出, G1收集器除了并发标记外, 其余阶段也是要完全暂停用户线程的,换言之, 它并非纯粹地追求低延迟, 官方给它设定的目标是在延迟可控的情况下获得尽可能高的吞吐量。
JVM仅指定新生代垃圾收集器的情况下,默认老年代采用Serial Old垃圾收集器(带压缩):
Serial (DefNew) + Serial Old(Serial Mark Sweep Compact)
Parallel (ParNew) + Serial Old(Serial Mark Sweep Compact)
Parallel Scavenge (PSYoungGen) + Serial Old(Serial Mark Sweep Compact (PSOldGen))
注:在Parallel Scavenge收集器架构中本身有PS MarkSweep收集器来进行老年代收集,但由于PS MarkSweep与Serial Old实现非常接近,因此官方的许多资料都直接以Serial Old代替PS MarkSweep进行讲解。
Parallel Scavenge (PSYoungGen) + Parallel Mark Sweep Compact (ParOldGen)
Serial (DefNew) + CMS(Concurrent Mark Sweep)
Parallel (ParNew) + CMS(Concurrent Mark Sweep) + Serial Old(Serial Mark Sweep Compact)
-XX:+UseG1GC
-XX:+UseConcMarkSweepGC(该参数隐式启用-XX:+UseParNewGC)
-XX:+UseParallelOldGC(该参数隐式启用-XX:+UseParallelGC)
下面对这七种垃圾收集器进行了一个总结,具体如下表所示。
收集器 | 串行、并行、并发 | 新生代/老年代 | 算法 | 目标 | 使用场景 |
---|---|---|---|---|---|
Serial | 串行 | 新生代 | 复制算法 | 响应速度优先 | 单CPU环境下的Client模式 |
ParNew | 并行 | 新生代 | 复制算法 | 响应速度优先 | 多CPU环境时再Server模式下与CMS配合 |
Parallel Scavenge | 并行 | 新生代 | 复制算法 | 吞吐量优先 | 在后台运算而不需要太多交互的任务 |
Serial Old | 串行 | 老年代 | 标记-整理 | 响应速度优先 | 单CPU环境下的Client模式 CMS的后备预案 |
Parallel Old | 并行 | 老年代 | 标记-整理 | 吞吐量优先 | 在后台运算而不需要太多交互的任务 |
CMS | 并发 | 老年代 | 标记-清除 | 响应速度优先 | 集中在互联网站或B/S系统服务端上 |
G1 | 并发 | 新生代/老年代 | 标记-整理/复制算法 | 响应速度优先 | 面向服务端应用,用来替换CMS |
参考
HotSpot的7种垃圾收集器组合
浅析经典JVM垃圾收集器-Serial/ParNew/Parallel Scavenge/Serial Old/Parallel Old/CMS/G1
https://blogs.oracle.com/
https://www.oracle.com/webfolder/technetwork/tutorials/obe/java/gc01/index.html
https://www.splunk.com/en_us/products/apm-application-performance-monitoring.html?source=plumbr
《深入理解Java虚拟机 JVM高级特性与最佳实践》周志明
《Java性能权威指南》
Java之CMS GC的7个阶段:https://mp.weixin.qq.com/s/vmnBlrM7pTtVuyQU-GTcPw