实际上,垃圾收集器(GC,Garbage Collector)是和具体 JVM 实现紧密相关的,不同厂商 (IBM、Oracle),不同版本的 JVM,提供的选择也不同。一般我们说的 JVM 指的就是 Oracle JDK 的 JVM。
- 新生代收集器:Serial、ParNew、Parallel Scavenge
- 老年代收集器:Serial Old、Parallel Old、CMS
- 整堆收集器:G1
新生代收集器
Serial
- 特点:
- 采用复制算法
- 单线程收集
- 应用场景:
- 简单高效(与其他收集器的单线程相比)
- 对于限定单个CPU的环境来说,Serial收集器没有线程交互(切换)开销,可以获得最高的单线程收集效率
- 在用户的桌面应用场景中,可用内存一般不大(几十M至一两百M),可以在较短时间内完成垃圾收集(几十MS至一百多MS),只要不频繁发生,这是可以接受的
- 启用参数:
-XX:+UseSerialGC
ParNew
- 特点:
- 除了多线程外,其余的行为、特点和Serial收集器一样
- 应用场景:
- 在Server模式下,ParNew收集器是一个非常重要的收集器,因为除Serial外,目前只有它能与CMS收集器配合工作
- 在单个CPU环境中,不会比Serial收集器有更好的效果,因为存在线程交互开销
- 启用参数:
-XX:+UseParNewGC
Parallel Scavenge
- 特点:
- 采用复制算法
- 多线程收集
- 应用场景:
- 高吞吐量为目标,即减少垃圾收集时间,让用户代码获得更长的运行时间
- 当应用程序运行在具有多个CPU上,对暂停时间没有特别高的要求时,即程序主要在后台进行计算,而不需要与用户进行太多交互
- 启用参数:
-XX:+UseParallelGC
- 其他参数:
- 设置垃圾收集时间占总时间的比率:
-XX:GCTimeRatio=N // GC 时间和用户时间比例 = 1 / (N+1)
- 控制最大垃圾收集停顿时间:
-XX:MaxGCPauseMillis=value //大于0的毫秒数
- 设置垃圾收集时间占总时间的比率:
老年代收集器
CMS
- 特点:
- 基于”标记-清除”算法(不进行压缩操作,产生内存碎片),以获取最短回收停顿时间为目标
- 并发收集、低停顿
- 需要更多的内存
- 应用场景:
- 与用户交互较多的场景
- 希望系统停顿时间最短,注重服务的响应速度
- 启用参数:
-XX:+UseConcMarkSweepGC
,年轻代自动开启ParNew:-XX:-UseParNewGC
从 Java 9 开始,不推荐使用 CMS 垃圾收集器。因此,如果我们尝试使用,JVM 将输出警告消息。此外,Java 14 完全放弃了 CMS 支持
Serial Old
- 特点
- 采用”标记-整理”算法
- 单线程收集
- 应用场景:
- 主要用于Client模式
- 启用参数:CMS失败时启用
Parallel Old
- 特点:
- 采用”标记-整理”算法
- 多线程收集
- 应用场景:
- JDK1.6及之后用来代替老年代的Serial Old收集器,特别是在Server模式,多CPU的情况下
- 这样在注重吞吐量以及CPU资源敏感的场景,就有了Parallel Scavenge加Parallel Old收集器的”给力”应用组合
- 启用参数:
-XX:+UseParallelOldGC
整堆收集器
G1
- 特点:
- 并行与并发
- 分代收集,收集范围包括新生代和老年代
- 结合多种垃圾收集算法,空间整合,不产生碎片(从整体看,是基于标记-整理算法;从局部(两个Region间)看,是基于复制算法)
- 可预测的停顿:低停顿的同时实现高吞吐量
- 应用场景:
- 面向服务端应用,针对具有大内存、多处理器的机器
- 最主要的应用是为需要低GC延迟,并具有大堆的应用程序提供解决方案
- 启用参数:
-XX:+UseG1GC