1. GC分类与性能指标
1.1 垃圾回收器概述
垃圾回收器是JVM内存管理的核心组件,其本质是通过特定算法实现以下三个核心功能:
- 内存区域划分
- 对象存活判定
- 内存回收策略
1.2 垃圾收集器分类
两种关键分类维度:
- 执行方式 :
- 串行:单线程执行,全程STW
- 并行:多线程并行回收
- 并发:与应用线程交替执行
- 内存管理策略 :
- 分代式(Generational)
- 分区式(Region-based)
1.3 评估GC的性能指标
三大核心指标:
- 吞吐量(Throughput)
- 公式:
<font style="background-color:rgb(252, 252, 252);">吞吐量 = 用户代码运行时间 / (用户代码运行时间 + GC时间)</font>
- 生产系统通常要求>90%
- 公式:
- 暂停时间(Pause Time)
- 单次GC导致的应用停顿时间
- 关键系统要求<200ms
- 内存占用(Footprint)
- JVM堆内存的峰值使用量
指标间的关系:
- 吞吐量 vs 延迟:通常呈反比关系
- 吞吐量 vs 内存:增大内存可提升吞吐量但增加回收成本
2. 不同的垃圾回收器概述
2.1 垃圾回收器发展史
关键发展阶段:
- 单线程时代(1998-2004):Serial收集器主导
- 吞吐量优先(2002-2011):Parallel Scavenge崛起
- 低延迟革命(2004-2017):CMS和G1的博弈
- 新一代回收器(2018至今):ZGC、Shenandoah实现亚毫秒级停顿
2.2 7种经典的垃圾收集器
经典收集器矩阵:
收集器 | 算法 | 线程模式 | 适用场景 |
---|---|---|---|
Serial | 复制 | 串行 | Client模式 |
ParNew | 复制 | 并行 | CMS搭档 |
Parallel Scavenge | 复制 | 并行 | 吞吐量优先 |
Serial Old | 标记-整理 | 串行 | Serial后备 |
Parallel Old | 标记-整理 | 并行 | Parallel最佳拍档 |
CMS | 标记-清除 | 并发 | 低延迟系统 |
G1 | 分区算法 | 并发 | 全场景 |
2.3 分代与收集器关系
关键组合规则:
- 新生代与老年代收集器必须兼容
- 连线组合关系:
- Serial/Serial Old
- ParNew/CMS
- Parallel Scavenge/Parallel Old
- G1独立运作
2.4 组合关系示意图
允许的组合方式:
- 红色警戒线(禁止组合):
- ParNew与Parallel Old
- CMS与Serial Old
- 推荐生产组合:
- Parallel Scavenge + Parallel Old(JDK8默认)
- ParNew + CMS(已逐步淘汰)
- G1(JDK9+默认)
2.5 查看默认垃圾收集器
方法一:命令行参数
bash
java -XX:+PrintCommandLineFlags -version
方法二:GC日志分析
java
// 添加JVM参数
-XX:+PrintGCDetails
示例输出解读:
plain
// Parallel收集器特征
PSYoungGen -> Parallel Scavenge
ParOldGen -> Parallel Old
// G1收集器特征
Garbage-First (G1)
不同版本的默认变化:
3. Serial回收器:串行回收
核心原理图解
技术特征:
- 单线程工作模式(GC线程仅使用1个CPU核心)
- 全程STW(暂停所有应用线程)
- 新生代使用复制算法(Eden + Survivor)
- 老年代使用标记-整理算法(Serial Old)
启用参数:
bash
-XX:+UseSerialGC
适用场景:
- 客户端模式(Client VM)
- 内存<100MB的简单应用
- 嵌入式设备等资源受限环境
优劣对比:
4. ParNew回收器:并行回收
并行回收机制
核心改进:
- Serial收集器的多线程版本(并行执行GC)
- 默认启用线程数 = CPU核心数(可通过
<font style="background-color:rgb(252, 252, 252);">-XX:ParallelGCThreads</font>
调整)
组合关系:
关键参数:
bash
-XX:+UseParNewGC
-XX:ParallelGCThreads=4
典型应用:
- JDK7及之前版本与CMS组合使用
- 服务端多核环境(但逐渐被G1替代)
5. Parallel回收器:吞吐量优先
体系结构
设计哲学:
- 吞吐量最大化目标:
<font style="background-color:rgb(252, 252, 252);">吞吐量 = 用户代码运行时间/(用户代码时间+GC时间)</font>
- 自适应调节策略(Auto-tuning):
- 自动调整堆大小
- 动态改变晋升阈值
核心参数:
bash
-XX:+UseParallelGC
-XX:+UseParallelOldGC
-XX:MaxGCPauseMillis=200 # 最大停顿时间目标
-XX:GCTimeRatio=99 # GC时间占比(1/(1+99))
工作流程:
6. CMS回收器:低延迟
四阶段并发收集
关键参数:
bash
-XX:+UseConcMarkSweepGC
-XX:CMSInitiatingOccupancyFraction=70 # 老年代触发阈值
-XX:+UseCMSCompactAtFullCollection # FullGC时压缩内存
6.1 CMS优点
6.2 CMS弊端
典型问题处理:
- 并发模式失败 (Concurrent Mode Failure)
- 解决方案:调低
<font style="background-color:rgb(252, 252, 252);">-XX:CMSInitiatingOccupancyFraction</font>
- 解决方案:调低
- 晋升失败 (Promotion Failed)
- 解决方案:增大Survivor空间或开启
<font style="background-color:rgb(252, 252, 252);">-XX:+CMSParallelRemarkEnabled</font>
- 解决方案:增大Survivor空间或开启
6.3 参数调优表
参数 | 默认值 | 说明 |
---|---|---|
-XX:+CMSParallelInitialMarkEnabled | true | 初始标记多线程加速 |
-XX:+CMSScavengeBeforeRemark | false | 重新标记前执行Young GC |
-XX:+UseCMSInitiatingOccupancyOnly | false | 仅用阈值触发不自动调整 |
7. G1回收器:区域化分代式
7.1 G1回收器的特点(优势)
核心创新点:
- Region分区机制:将堆划分为2048个等大小区域(1MB~32MB可调)
- 动态角色转换:每个Region可随时作为Eden/Survivor/Old/Humongous使用
- 回收优先级:根据回收价值(GC效率)排序Region
7.2 G1的缺点
性能拐点:
- 堆内存<6GB时,CMS可能表现更好
- 堆内存>6GB时,G1优势显现
7.3 G1参数设置
关键参数表:
参数 | 默认值 | 说明 |
---|---|---|
-XX:G1HeapRegionSize | 根据堆计算 | 设置Region大小(2^N) |
-XX:MaxGCPauseMillis | 200ms | 最大停顿时间目标 |
-XX:InitiatingHeapOccupancyPercent | 45 | 老年代占用阈值触发并发周期 |
-XX:G1ReservePercent | 10 | 预留内存防溢出 |
7.4 G1常见操作步骤
7.5 G1适用场景
典型应用案例:
- 电商大促系统(堆内存32GB,要求GC停顿<200ms)
- 金融交易系统(需要稳定低延迟)
- 长期运行的后台服务(避免内存碎片)
7.6 分区Region:化整为零
Humongous对象处理:
- 超过Region 50%大小的对象
- 存放在连续Humongous区
- 优先纳入回收范围
7.7 G1垃圾回收过程
7.8 Remembered Set
跨代引用处理:
- 每个Region维护一个RSet
- 使用写屏障(Write Barrier)技术维护
- 避免全堆扫描
7.9 年轻代GC过程
阶段耗时占比:
7.10 G1回收过程二:并发标记过程
关键机制:
- SATB算法:在标记开始时建立快照,新分配的对象默认标记为存活
- 并行标记线程 :默认线程数 =
<font style="background-color:rgb(252, 252, 252);">-XX:ConcGCThreads</font>
(建议设置为ParallelGCThreads的1/4)
7.11 G1回收过程三:混合回收
阶段特点:
- 同时处理年轻代和老年代Region
- 多轮回收机制(最多8轮,通过
<font style="background-color:rgb(252, 252, 252);">-XX:G1MixedGCCountTarget</font>
控制) - 动态调整回收比例:根据
<font style="background-color:rgb(252, 252, 252);">-XX:G1HeapWastePercent</font>
(默认5%)决定是否停止回收
7.12 G1回收可选的过程四:Full GC
规避Full GC策略:
- 增加堆内存
<font style="background-color:rgb(252, 252, 252);">-Xmx</font>
- 降低IHOP阈值
<font style="background-color:rgb(252, 252, 252);">-XX:InitiatingHeapOccupancyPercent</font>
- 增加预留内存
<font style="background-color:rgb(252, 252, 252);">-XX:G1ReservePercent=15</font>
- 避免大对象直接进入老年代
<font style="background-color:rgb(252, 252, 252);">-XX:G1HeapRegionSize=4M</font>
7.14 G1回收器优化建议
参数调优矩阵:
问题现象 | 调优参数 | 预期效果 |
---|---|---|
频繁Mixed GC | 提高<font style="background-color:rgb(252, 252, 252);">-XX:InitiatingHeapOccupancyPercent</font> |
减少混合回收触发频率 |
Remark阶段耗时过长 | <font style="background-color:rgb(252, 252, 252);">-XX:+CMSScavengeBeforeRemark</font> |
减少重新标记工作量 |
并发模式失败 | 增加<font style="background-color:rgb(252, 252, 252);">-XX:G1ReservePercent</font> |
预留更多内存防止溢出 |
Young GC时间过长 | 调整<font style="background-color:rgb(252, 252, 252);">-XX:G1NewSizePercent</font> |
优化年轻代比例 |
8. 垃圾回收器总结
8.1 7种经典垃圾回收器对比
核心差异总结表:
特性\收集器 | Serial | ParNew | Parallel | CMS | G1 |
---|---|---|---|---|---|
线程模式 | 串行 | 并行 | 并行 | 并发 | 并发 |
分代策略 | 物理分代 | 物理分代 | 物理分代 | 物理分代 | 逻辑分代 |
内存碎片处理 | 无 | 无 | 无 | 有 | 无 |
最大堆限制 | 无 | 无 | 无 | 4-8G | 可达TB级 |
默认使用版本 | Client | JDK7 | JDK8 | 逐步淘汰 | JDK9+ |
8.2 垃圾回收器组合规则
组合使用原则:
- 新生代与老年代收集器必须兼容(算法、内存布局)
- 启用参数需同时指定:
<font style="background-color:rgb(252, 252, 252);">-XX:+UseSerialGC</font>
(自动组合Serial+Serial Old) - G1、ZGC等新一代收集器无需组合
8.3 选择收集器的决策树
9. GC日志分析
Minor GC日志示例
plain
[GC pause (G1 Evacuation Pause) (young), 0.0023453 secs]
[Parallel Time: 1.8 ms, GC Workers: 8]
[GC Worker Start (ms): Min: 100.1, Avg: 100.2, Max: 100.3]
[Ext Root Scanning (ms): Min: 0.1, Avg: 0.3, Max: 0.5]
[Update RS (ms): Min: 0.0, Avg: 0.1, Max: 0.2]
[Processed Buffers: Min: 0, Avg: 1.2, Max: 3]
[Scan RS (ms): Min: 0.0, Avg: 0.1, Max: 0.2]
[Code Root Scanning (ms): Min: 0.0, Avg: 0.0, Max: 0.0]
[Object Copy (ms): Min: 0.8, Avg: 1.0, Max: 1.2]
[Termination (ms): Min: 0.0, Avg: 0.1, Max: 0.2]
[GC Worker Other (ms): Min: 0.0, Avg: 0.0, Max: 0.0]
[GC Worker Total (ms): Min: 1.6, Avg: 1.7, Max: 1.8]
关键字段解析:
<font style="background-color:rgb(252, 252, 252);">G1 Evacuation Pause</font>
:G1的年轻代回收阶段<font style="background-color:rgb(252, 252, 252);">GC Workers: 8</font>
:并行GC线程数<font style="background-color:rgb(252, 252, 252);">Object Copy</font>
:对象复制耗时(主要性能指标)
Full GC日志示例
plain
[Full GC (Allocation Failure)
[PSYoungGen: 1024K->0K(2048K)]
[ParOldGen: 3072K->4096K(4096K)]
4096K->4096K(6144K),
[Metaspace: 256K->256K(1024K)],
0.123456 secs]
问题诊断点:
<font style="background-color:rgb(252, 252, 252);">Allocation Failure</font>
:内存分配失败触发- ParOldGen回收后内存增加:内存泄漏迹象
- Metaspace数据不变:可能类加载器未释放
10. 垃圾回收器新发展
10.1 ZGC核心特性
版本演进:
- JDK11:实验功能
- JDK15:生产可用
- JDK17:支持分代收集(ZGC Generational)
10.2 Shenandoah GC
核心创新:
- 并发压缩算法
- 连接矩阵替代RSet
- 增量回收机制
与G1对比:
10.3 AliGC(阿里优化版)
商业版增强功能:
- 多租户隔离回收
- 弹性堆内存管理
- 基于AI的预测回收
11. 常见问题与解决方案
问题排查表
现象 | 可能原因 | 解决方案 |
---|---|---|
频繁Full GC | 内存泄漏/过小堆 | 堆dump分析/增加-Xmx |
Young GC时间过长 | 过早提升/大对象 | 调整SurvivorRatio/检查大对象 |
CMS并发模式失败 | 回收速度跟不上分配速度 | 降低触发阈值/增加并发线程 |
G1混合回收效率低 | Region存活数据过多 | 调整IHOP阈值/减少Humongous分配 |
12. 高频面试问题与解答
Q1:CMS和G1的主要区别是什么?
答案:
- 内存布局:CMS物理分代 vs G1逻辑分代
- 回收算法:CMS标记-清除 vs G1复制+整理
- 停顿目标:CMS关注低延迟 vs G1可预测停顿
- 堆内存:CMS适合中等堆 vs G1适合大堆
Q2:如何选择垃圾回收器?
决策流程:
- 堆大小:<6GB选CMS,>6GB选G1
- 延迟要求:要求亚秒级选ZGC/Shenandoah
- JDK版本:JDK8用Parallel/CMS,JDK11+用G1/ZGC
Q3:-XX:+UseCompressedOops的作用?
解析:
- 启用压缩指针(32位指针存64位地址)
- 节省内存(提升约20%)
- 堆内存<32GB时自动生效