评估GC性能指标
- 吞吐量:运行用户代码的时间占总运行时间的比例
- 暂停时间:执行垃圾收集时,程序的工作线程被暂停的时间;
- 内存占用:Java堆区所占内存的大小;
存在实线的是:可以搭配使用的垃圾回收器;
存在虚线的是:已经废弃或者即将废弃的组合;
查看默认的垃圾回收器:
-XX:+PrintCommandLineFlags
//查看命令行相关参数,包含使用的垃圾收集器
-XX:InitialHeapSize=132910912 -XX:MaxHeapSize=2126574592 -XX:+PrintCommandLineFlags -XX:+UseCompressedClassPointers -XX:+UseCompressedOops -XX:-UseLargePagesIndividualAllocation -XX:+UseParallelGC
所以,在JDK1.8版本下,使用的GC垃圾回收器搭配方案为:Parallel Scavenge GC 与 Parallel Old GC。
JDK1.8版本下,使用的GC垃圾回收器是G1 GC。
Serial回收器:串行回收
- Serial收集器是最基本、历史最悠久的垃圾收集器。JDK1.3之前回收新生代的唯一的选择;
- Serial收集器作为HotSpot中Client模式下的默认新生代垃圾收集器;
- Serial收集器采用复制算法、串行回收和"Stop The World"机制的方式执行内存回收;
- 除了年轻代之外,Serial收集器还提供用于执行老年代垃圾收集的Serial Old收集器,内存回收算法采用标记压缩算法;
- Serial Old是运行在Client模式下默认的老年代的垃圾回收器;
- Serial Old在Server模式下主要有两个用途:(1)与新生代的Parallel Scavenge配合使用;(2)作为老年代CMS收集器的后备垃圾收集方案;
ParNew回收器:并行回收
- 如果说Serial GC是年轻代中的单线程垃圾收集器,那么ParNew收集器则是Serial收集器的多线程版本;
- Par是Parallel的缩写,New是只能处理新生代;
- ParNew收集器除了采用并行回收的方式执行内存回收外,两款垃圾收集器之间几乎没有任何区别。ParNew收集器在年轻代中同样也是采用复制算法和Stop The World机制;
- ParNew是很多JVM运行在Server模式下新生代的默认垃圾收集器。
ParNew 和 Serial Old的搭配。
Parallel Scavenge回收器:吞吐量优先
- HotSpot的年轻代中除了拥有ParNew收集器是基于并行回收的以外,Parallel Scavenge收集器同样采用了复制算法、并行回收和Stop The World机制;
- 那么Parallel Scavenge收集器的出现是否多此一举?
- 和ParNew收集器不同,Parallel Scavenge收集器的目标则是达到一个可控制的吞吐量,它也被称为吞吐量优先的垃圾收集器;
- 自适应调节策略也是Parallel Scavenge与ParNew一个重要区别。
- 高吞吐量可以高效率的利用CPU时间,尽快完成程序的运算任务,主要适合在后台运算而不需要太多交互的任务。因此,常见在服务器环境中使用,比如那些执行批量处理、订单处理、工资支付、科学计算的应用程序;
- Parallel Scavenge收集器在JDK1.6提供了用于执行老年代垃圾收集的Parallel Old收集器,用来代替老年代的Serial Old收集器;
- Parallel Old收集器采用了标记压缩算法,同样也是基于并行回收和Stop The World机制;
参数配置:
-XX:+UseParallelGC
# 手动指定年轻代使用Parallel并行收集器执行内存回收
-XX:+UseParallelOldGC
# 手动指定老年代使用并行回收器
# 默认Jdk1.8开启,默认开启一个,另一个自动被激活
-XX:ParallelGCThreads
# 设置年轻代并行收集器的线程数
-XX:+UseAdaptiveSizePolicy
# 设置Parallel Scavenge垃圾收集器具有自适应调节策略
CMS回收器:低延迟
- 在JDK1.5时期,HotSpot推出了一款CMS(Concurrent-Mark-Sweep)收集器,第一款真正意义上的并发收集器,第一次实现了让垃圾收集线程和用户线程同时工作。
- CMS收集器的关注点就是尽可能缩短垃圾收集时用户线程的停顿时间;
- 采用标记-清除算法,并且也会Stop-The-World;
不幸的是,CMS作为老年代的收集器,无法与新生代收集器Parallel Scavenge配合工作,所以在JDK1.5时,使用CMS来收集老年代时,新生代只能选择ParNew或者Serial收集器中的一个。
在G1出现之前,CMS使用还是非常广泛的。
CMS工作原理
CMS优点:
- 并发收集
- 低延迟
CMS的弊端:
- 会产生内存碎片;
- CMS收集器对CPU资源非常敏感;
- CMS收集器无法处理浮动垃圾,可能出现"Concurrent Mode Failure"失败。在并发标记阶段由于程序的工作线程和垃圾收集线程是同时运行或交叉运行的,那么在并发标记阶段如果产生新的垃圾对象,CMS将无法对这些垃圾对象进程标记,最终导致这些新产生的垃圾对象没有被及时回收,只能下次执行GC时释放这些之前未被回收的内存空间。
在Java9中,CMS被标记为Deprecate。
在Java14中,删除了CMS垃圾回收器。
G1回收器:区域化分代式
G1 Garbage First。
Java9以后默认垃圾回收器,取代了Parallel + Parallel Old组合。
分区Region:化整为零
使用G1收集器时,它将整个Java堆划分为约2048个大小相同的独立Region块,每个Region块大小根据堆空间的实际大小而定,整体被控制在1MB-32MB之间,且为2的N次幂。
可以通过-XX:G1HeapRegionSize
设定,所有的Region大小相同,且在JVM生命周期内不会被改变。
虽然还保留有新生代和老年代的概念,但是新生代和老年代不再是物理隔离的了,它们都是一部分Region,不需要连接的集合。通过Region的动态分配方式实现逻辑上的连续。
GC日志分析
-XX:+PrintGCDetails