一、GC 核心基础(必背)
1. 为什么需要 GC?
- Java 对象在堆内存 创建,不回收会导致 OOM(内存溢出)
- GC 自动回收无用对象内存,避免内存泄漏,保证程序长期运行
- 对比 C/C++ 手动管理内存:GC 更安全,但会产生 STW(停顿)
2. 回收什么?------ 无用对象判定
JVM 只用 可达性分析算法,不用引用计数。
表格
| 算法 | 原理 | 优点 | 缺点 |
|---|---|---|---|
| 引用计数 | 对象被引用 + 1,失效 - 1,为 0 则回收 | 简单高效 | 无法解决循环引用 |
| 可达性分析 | 从 GC Roots 遍历,不可达对象判定为垃圾 | 安全准确,JVM 默认 | 实现稍复杂 |
GC Roots 固定 4 类
- 虚拟机栈局部变量引用
- 方法区静态属性引用
- 方法区常量引用
- 本地方法栈 JNI 引用
3. 怎么回收?------ 三大基础算法
所有 GC 都基于这 3 步,只是实现不同:
- 标记:标记存活 / 垃圾对象
- 清除:回收垃圾内存(会产生碎片)
- 整理:移动对象,消除内存碎片
核心矛盾 标记 / 清除 / 整理必须 STW(Stop The World)暂停用户线程 垃圾收集器 = 在 回收效率、内存碎片、停顿时间 之间做平衡
二、JVM 内存分代模型(核心)
堆内存 = 年轻代 + 老年代元空间不在堆内,本文不重点讲。
表格
| 分代 | 对象特点 | 回收频率 | 核心需求 |
|---|---|---|---|
| 年轻代 | 新对象、生命周期短 | 极高(Minor GC) | 回收快、停顿短 |
| 老年代 | 长期存活、大对象 | 低(Full GC) | 无碎片、效率稳 |
三、7 大垃圾收集器 超详细对比(面试必考)
分类总览
- 年轻代:Serial、ParNew
- 老年代:Serial Old、Parallel Old
- 整堆回收:CMS、G1、ZGC/Shenandoah
3.1 年轻代收集器
① Serial GC(串行)
- 单线程回收,全程 STW
- 算法:复制算法
- 搭配:老年代 Serial Old
- 优点:简单、轻量、无线程开销
- 缺点:停顿极长,不利用多核
- 场景:堆内存 <1GB、嵌入式、桌面应用
- 参数:
-XX:+UseSerialGC
② ParNew GC(并行)
- Serial 多线程版本
- 算法:复制算法
- 唯一能和 CMS 配合的年轻代收集器
- 优点:多核下停顿更短
- 缺点:仍有 STW,单核不如 Serial
- 场景:多核服务器 + CMS 组合
- 参数:
-XX:+UseParNewGC
3.2 老年代收集器
① Serial Old(串行)
- 单线程、标记 - 整理算法
- 优点:无碎片、实现简单
- 缺点:停顿极长
- 场景:小内存、Serial GC 配套使用
② Parallel Old(并行)
- JDK8 默认老年代收集器
- 多线程、标记 - 整理算法
- 搭配:Parallel Scavenge(年轻代)
- 目标:高吞吐量
- 优点:多核高效、无碎片
- 缺点:停顿时间不可控
- 场景:后台计算、批处理、数据任务
- 参数:
-XX:+UseParallelOldGC
3.3 整堆收集器(最重要)
① CMS GC(并发标记清除)
- 目标:低延迟
- 算法:标记 - 清除(不整理,会产生碎片)
- JDK9 废弃,JDK14 移除
4 阶段(2 段 STW + 2 段并发)
- 初始标记(STW,极快)
- 并发标记(和用户线程一起跑)
- 重新标记(STW,修正标记)
- 并发清除(和用户线程一起跑)
优点
- 停顿极短
- 并发回收,不阻塞业务
缺点(必背)
- 内存碎片(最致命)
- 占用 CPU,降低吞吐量
- 无法处理浮动垃圾
- concurrent mode failure 会退化为 Serial Old
场景 :Web 接口、低延迟要求高的服务参数 :-XX:+UseConcMarkSweepGC
② G1 GC(Garbage-First)
- JDK9+ 默认收集器
- 目前生产环境首选
- 设计:分区内存(Region),打破固定分代
- 算法:标记 - 整理 + 复制
- 目标:兼顾吞吐量 + 低延迟
核心流程
- 初始标记(STW)
- 并发标记
- 最终标记(STW)
- 筛选回收(STW,优先回收垃圾最多的 Region)
- 并发清理
优点(必背)
- 可控制停顿时间
- 无内存碎片
- 支持大堆(8GB~100GB)
- 动态调整年轻 / 老年代
缺点
- 占额外内存
- CPU 要求高
场景 :微服务、分布式、大型 Web、通用服务器参数 :-XX:+UseG1GC
③ ZGC / Shenandoah GC(新一代超低延迟)
- JDK11+ ZGC(官方主推)
- JDK12+ Shenandoah(OpenJDK)
- 停顿时间:微秒级(<10ms → <0.01ms)
- 支持 TB 级堆内存
- 几乎全程并发,标记 / 复制都不 STW
优点
- 延迟极致
- 堆越大优势越明显
- 无碎片
场景 :金融交易、实时计算、超大堆服务参数:
- ZGC:
-XX:+UseZGC - Shenandoah:
-XX:+UseShenandoahGC
四、垃圾收集器 最强对比表
表格
| 收集器 | 类型 | 算法 | 优点 | 缺点 | 适用场景 | JDK 默认 |
|---|---|---|---|---|---|---|
| Serial | 年轻代 | 复制 | 简单轻量 | 单线程、停顿长 | 小内存、嵌入式 | - |
| ParNew | 年轻代 | 复制 | 多核并行 | 停顿不可控 | 配合 CMS | - |
| SerialOld | 老年代 | 标记 - 整理 | 无碎片 | 停顿极长 | 小内存 | - |
| ParallelOld | 老年代 | 标记 - 整理 | 高吞吐 | 停顿较长 | 后台任务 | JDK8 |
| CMS | 整堆 | 标记 - 清除 | 低延迟 | 内存碎片 | Web 服务 | 废弃 |
| G1 | 整堆 | 标记 - 整理 + 复制 | 均衡、无碎片 | 占内存 | 通用生产 | JDK9+ |
| ZGC | 整堆 | 染色指针 | 微秒级停顿 | 吞吐量略低 | 低延迟大堆 | JDK17+ |
五、实战选型指南(直接照抄用)
1. 优先用 JDK 默认
- JDK8:Parallel + Parallel Old(吞吐量优先)
- JDK9+:G1(通用首选)
2. 按业务场景选
- 低延迟优先 (Web / 接口 / 秒杀)
- 堆 <16G → G1
- 堆 ≥16G → ZGC
- JDK8 → CMS
- 吞吐量优先(批处理 / 计算任务)→ Parallel + Parallel Old
- 小内存(<1GB)→ Serial + Serial Old
- 超大堆(≥32GB)→ ZGC(JDK11+)
3. 避坑提醒
- 不要盲目追求低延迟
- 不要乱调 GC 参数
- CMS 已废弃,一律用 G1 替代
六、终极总结(一句话背会)
- Serial:单线程、小内存、简单
- Parallel:多线程、高吞吐、后台任务
- CMS:低延迟、有碎片、已废弃
- G1 :均衡通用、无碎片、生产首选
- ZGC:极致低延迟、未来趋势