一句话总结
JVM 垃圾回收器按分代可分为:新生代(Serial、ParNew、Parallel Scavenge)、老年代(Serial Old、Parallel Old、CMS)、整堆(G1、ZGC、Shenandoah)。CMS(JDK 5-8)以最短 STW 为目标,使用标记-清除算法,有碎片和浮动垃圾问题。G1(JDK 9+ 默认)将堆划分为 Region,优先回收垃圾最多的 Region,可预测停顿时间。ZGC(JDK 11+)目标是将 STW 控制在 10ms 以内。
初级理解
七大垃圾回收器一览
| 收集器 | 作用区域 | 算法 | 线程 | 特点 |
|---|---|---|---|---|
| Serial | 新生代 | 复制 | 单线程 | 简单高效,适合客户端 |
| ParNew | 新生代 | 复制 | 多线程 | Serial 的多线程版,配合 CMS |
| Parallel Scavenge | 新生代 | 复制 | 多线程 | 关注吞吐量,自适应调节 |
| Serial Old | 老年代 | 标记-整理 | 单线程 | 客户端模式备用 |
| Parallel Old | 老年代 | 标记-整理 | 多线程 | 配合 Parallel Scavenge |
| CMS | 老年代 | 标记-清除 | 多线程 | 低停顿,JDK 14 移除 |
| G1 | 整堆 | 标记-整理+复制 | 多线程 | 可预测停顿,JDK 9 默认 |
经典组合
中级深入
CMS 工作流程
G1 工作流程
高级拓展
CMS vs G1 深度对比
| 特性 | CMS | G1 |
|---|---|---|
| 内存布局 | 连续的新生代+老年代 | 划分为多个 Region |
| 回收算法 | 标记-清除(有碎片) | 标记-整理+复制(无碎片) |
| 停顿预测 | 不可预测 | 可设置停顿目标 |
| 大对象 | 直接进入老年代 | Humongous Region(多个连续 Region) |
| 记忆集 | 卡表 | 卡表 + 哈希表(更占内存) |
| 适用堆 | < 6GB | 6GB ~ 几十 GB |
| JDK 状态 | JDK 14 移除 | JDK 9+ 默认 |
ZGC 和 Shenandoah
实战场景
如何选择垃圾回收器?
| 场景 | 推荐 | 理由 |
|---|---|---|
| 客户端小应用 | Serial | 单线程,内存小,简单高效 |
| 后台计算任务 | Parallel | 吞吐量优先,CPU 利用率高 |
| Web 应用(JDK 8) | CMS / G1 | 低延迟,减少用户感知停顿 |
| 大堆(> 6GB) | G1 | 可预测停顿,无碎片 |
| 超大堆(> 几十 GB) | ZGC | 亚毫秒级停顿 |
面试模拟
Q:CMS 和 G1 的区别?
A:1) 内存布局:CMS 是连续分代,G1 是 Region 化;2) 算法:CMS 标记-清除有碎片,G1 标记-整理+复制无碎片;3) 停顿:CMS 不可预测,G1 可设置停顿目标;4) 大对象:CMS 直接进老年代,G1 用 Humongous Region;5) 适用:CMS 适合 6GB 以下,G1 适合 6GB 以上;6) 状态:CMS 在 JDK 14 已移除。
Q:G1 的 Region 是什么?为什么叫 Garbage First?
A:G1 将堆划分为大小相等的 Region(1~32MB),每个 Region 可以是 Eden、Survivor、Old 或 Humongous。回收时对各个 Region 的回收价值(垃圾量)和成本(时间)排序,优先回收垃圾最多的 Region,所以叫 Garbage First。这样可以在有限停顿时间内回收尽可能多的垃圾。
Q:CMS 的 Concurrent Mode Failure 是什么?
A:CMS 并发清除时,用户线程仍在产生垃圾(浮动垃圾)。如果老年代剩余空间不足以容纳浮动垃圾,就会触发 Concurrent Mode Failure,JVM 会退化为 Serial Old 进行 Full GC,导致长时间 STW。解决:预留足够的老年代空间(-XX:CMSInitiatingOccupancyFraction 调低),或增大堆内存。