G1 GC工作原理:
- 内存布局
- 将堆划分为多个大小相等的Region(默认2048个,每个1-32MB)
- Region类型:Eden、Survivor、Old、Humongous(大对象)
- 大对象(超过Region 50%)直接分配到Humongous区域
-
GC过程
Young GC(Minor GC):
1 2 3 4 5 6 7
触发条件:Eden区满 回收范围:所有Young Region 过程: 1. 扫描GC Roots + RSet(Remembered Set) 2. 复制存活对象到Survivor或Old区 3. 清空Eden和回收的Survivor区 4. STW(Stop The World)时间可控
Mixed GC(混合GC):
1
2
3
4
5
6
7
触发条件:老年代占堆比例达到阈值(默认45%)
回收范围:所有Young Region + 部分Old Region
过程:
1. 初始标记(Initial Mark):STW,标记GC Roots
2. 并发标记(Concurrent Mark):并发执行,标记存活对象
3. 最终标记(Remark):STW,处理SATB(Snapshot-At-The-Beginning)
4. 筛选回收(Cleanup):选择回收价值最大的Region
Full GC:
1
2
3
4
5
6
7
8
9
10
11
12
13
触发条件:Mixed GC无法跟上分配速度、Metaspace不足
特点:完全STW,性能差
目标:尽量避免Full GC
-XX:+UseG1GC # 启用G1
-XX:MaxGCPauseMillis=200 # 最大停顿时间目标(毫秒)
-XX:G1HeapRegionSize=n # Region大小(1-32MB)
-XX:InitiatingHeapOccupancyPercent=45 # 触发Mixed GC的老年代占比
-XX:G1NewSizePercent=5 # 年轻代最小占比
-XX:G1MaxNewSizePercent=60 # 年轻代最大占比
-XX:G1MixedGCCountTarget=8 # Mixed GC回收次数
-XX:ConcGCThreads=n # 并发GC线程数
G1 vs CMS 对比:
| 维度 | G1 | CMS |
|---|---|---|
| 内存布局 | Region化,灵活 | 固定分代 |
| 停顿时间 | 可预测,可控制 | 不可预测 |
| 内存碎片 | 复制算法,无碎片 | 标记-清除,有碎片 |
| Full GC | 较少 | 频繁(碎片导致) |
| CPU开销 | 中等(RSet维护) | 低 |
| 适用场景 | 大堆(>6G),低延迟 | 中等堆,高吞吐 |
| 并发性 | 标记+回收并发 | 仅标记并发 |
选择G1的场景:
- 堆内存 ≥ 6GB
- 对响应时间敏感(如Web服务、在线交易)
- 需要可预测的停顿时间(如SLA要求P99 < 200ms)
- 避免Full GC导致的长时间停顿
选择CMS的场景:
- 堆内存 < 6GB
- 对吞吐量要求更高
- 已有稳定的CMS调优经验
- 注意:CMS在JDK9标记废弃,JDK14移除
实际案例: ``` 场景:电商订单服务,8G堆,QPS 5000 原配置:CMS,平均GC停顿300ms,P99停顿1s+
优化:
- 切换到G1:-XX:+UseG1GC -XX:MaxGCPauseMillis=200
- 结果:平均GC停顿150ms,P99停顿200ms
- 代价:CPU使用率提升5%(RSet维护)
结论:对于低延迟场景,G1是更好的选择