深入解剖 G1 收集器的分区模型与调优策略
JVM 垃圾收集系列之三 | 高并发低延迟系统的首选 GC 解法!
一、为什么我们需要 G1 垃圾收集器?
在传统 GC(如 CMS)中,我们常常面临的问题是:
- GC 停顿不可预测(Stop-The-World)
- 内存碎片严重,导致 Full GC 触发频繁
- 并发阶段对应用线程影响较大
为了解决这些问题,G1(Garbage First)作为 Java 7u4 引入的新一代垃圾收集器,于 JDK9 成为默认 GC,具备以下特性:
- 可预测的低延迟 GC
- 分区化的堆结构,减少碎片
- 并发、并行、多线程的回收方式
- 自动调整回收策略
二、G1 的核心设计理念:Region 分区模型
G1 如何划分堆内存?
G1 将整个堆划分为多个大小相等的 Region(区域),默认每个 Region 为 1MB~32MB,总数通常在 2048 个以内。
各 Region 的角色:
Region 类型 | 说明 |
---|---|
Eden | 新生对象首次分配的内存区域 |
Survivor | 新生代中从 Eden 存活下来的对象 |
Old | 老年代,存活时间长或大对象直接进入 |
Humongous | 超大对象(大于 Region 一半大小)所在区域,连续多个 Region 组成 |
Available | 空闲未使用的 Region |
内存示意图:
| Eden | Eden | Survivor | Old | Old | Humongous | Available | …
G1 不再是物理上划分新生代和老年代,而是逻辑上分类 Region,因此更加灵活和高效。
三、G1 的垃圾回收流程解析
Young GC(年轻代回收)
- 触发时机:Eden 区满
- 只回收 Eden 和部分 Survivor 区
- 并发 + 并行执行,暂停时间短
Mixed GC(混合回收)
- 回收 Eden、Survivor 以及部分 Old 区
- 在 Heap 使用率高时触发
- 是 G1 的关键性能优化点
Full GC(全堆回收)
- 不常见,一般在 G1 处理不过来、Humongous 太多时触发
- 使用单线程串行 GC,性能非常差
- 应尽量避免
四、G1 调优参数详解
基本启动参数
-XX:+UseG1GC # 启用 G1 收集器
-XX:MaxGCPauseMillis=200 # 目标最大 GC 停顿时间(默认 200ms)
-XX:InitiatingHeapOccupancyPercent=45 # 启动 Mixed GC 的堆占用阈值(默认 45%)
-XX:ParallelGCThreads=8 # 并行 GC 线程数
-XX:ConcGCThreads=2 # 并发标记线程数
容量控制参数
-Xms4g -Xmx4g # 固定堆大小,避免动态扩容
-XX:NewRatio=2 # 年轻代 : 老年代 = 1 : 2(也可使用 G1 自动调整)
五、如何判断 G1 回收效果好不好?
你可以从 GC 日志中分析如下信息:
[GC pause (G1 Evacuation Pause) (young) 1024M->512M(2048M), 0.050 secs]
判断标准:
指标 | 建议范围 |
---|---|
GC 停顿时间 | 小于目标 MaxGCPauseMillis |
Mixed GC 间隔 | 合理、稳定,不频繁 |
Humongous 区比例 | < 10%,避免大量超大对象产生 |
可视化工具推荐:
- GCEasy.io
- GCViewer
- JDK Flight Recorder (JFR)
- JVisualVM
G1 实战调优策略
初始建议配置(典型线上配置)
-XX:+UseG1GC
-XX:MaxGCPauseMillis=100
-XX:InitiatingHeapOccupancyPercent=45
-XX:G1HeapRegionSize=8M
-XX:+UnlockExperimentalVMOptions
-XX:+UseStringDeduplication
适合 G1 的场景:
场景 | 是否推荐使用 G1 |
---|---|
Web 服务(高并发) | ✅ 推荐 |
大内存中台系统 | ✅ 推荐 |
对 GC 停顿极敏感系统 | ✅ 推荐 G1 / ZGC |
桌面小程序 | ❌ 资源浪费,推荐 SerialGC |
调优流程:
- 开启 GC 日志并观察 Eden/Old 增长趋势
- 设置合适的堆大小,避免频繁 GC
- 调整 MaxGCPauseMillis 观察 STW 变化
- 控制对象分配,避免大量大对象直进老年代
- 使用 G1HeapRegionSize 控制碎片问题
七、注意事项与陷阱
问题 | 说明 |
---|---|
Humongous 对象过多 | 会导致频繁 Full GC,建议优化代码避免大对象 |
-Xms != -Xmx | 会导致堆扩容回收频繁,推荐设置相等 |
G1 未能达到 MaxGCPauseMillis | 说明 GC 压力大,需调大堆、优化代码分配 |
与 CMS 参数混用 | 无效!使用 G1 时应专注 G1 参数配置 |
八、总结:为什么 G1 是现代服务优选?
- 分区结构灵活
- 可预测的 GC 停顿
- 混合回收提升吞吐
- 支持并发标记、并发清理
- 自动调整内存分区,减轻调优压力
下一篇,垃圾回收(GC)基础原理,敬请关注!