12 JVM垃圾回收机制(下):G1回收器与调优实战

图片[1]-12 JVM垃圾回收机制(下):G1回收器与调优实战-速优课

在上一篇中,我们介绍了垃圾回收的基本原理和常用算法。本文将深入探讨 G1 回收器的设计原理、工作流程以及 JVM 调优的实战技巧。

一、G1 回收器的设计目标

G1 的核心特点

G1(Garbage First)是 Java 9 默认的垃圾回收器,设计目标是:

  1. 可预测停顿时间:可以设置最大停顿时间目标
  2. 高吞吐量:在保证停顿时间的前提下最大化吞吐量
  3. 无内存碎片:使用标记-整理算法
  4. 支持大堆内存:适用于 4GB 以上的堆内存

G1 与其他回收器的对比

回收器适用场景停顿时间内存碎片
Serial客户端、小堆较长
Parallel服务器、追求吞吐量较长
CMS追求低延迟较短
G1大堆、追求可控延迟可控
ZGC超大堆、追求极低延迟极低(<10ms)

二、G1 的内存布局

Region 分区

G1 将堆内存划分为多个大小相等的 Region:

┌─────────────────────────────────────────────────────────────┐
│                    G1 Heap Memory                           │
├─────────────────────────────────────────────────────────────┤
│  Region 0  │  Region 1  │  Region 2  │  ...   │  Region N   │
│  (Eden)    │  (Survivor) │  (Old)     │       │  (Humongous)│
└─────────────────────────────────────────────────────────────┘

Region 类型

类型说明
Eden新生代区域,新对象分配在此
Survivor新生代区域,存放存活的年轻对象
Old老年代区域,存放存活时间较长的对象
Humongous存放超大对象(超过 Region 大小的一半)

Region 大小

  • 默认根据堆大小自动计算(1MB ~ 32MB)
  • 可以通过 -XX:G1HeapRegionSize 参数手动设置

三、G1 的工作流程

新生代收集(Young GC)

触发条件

  • Eden 区满时

流程

  1. 扫描根:扫描 GC Roots
  2. 更新 Remembered Set:处理跨代引用
  3. 复制存活对象:将存活对象复制到 Survivor 区或 Old 区
  4. 清空 Eden 区:释放内存

并发标记周期

触发条件

  • 老年代占用率达到阈值(默认 45%)

流程

  1. 初始标记(Initial Mark)
    • 暂停所有应用线程
    • 标记 GC Roots 直接引用的对象
    • 记录 Remembered Set
  2. 并发标记(Concurrent Mark)
    • 与应用线程并发执行
    • 遍历对象图,标记所有存活对象
    • 使用 SATB(Snapshot-At-The-Beginning)技术
  3. 最终标记(Final Mark)
    • 暂停所有应用线程
    • 处理并发阶段新增的引用
  4. 筛选回收(Live Data Counting & Evacuation)
    • 计算每个 Region 的存活对象比例
    • 选择回收价值最高的 Region
    • 复制存活对象,释放空间

Mixed GC

在并发标记周期完成后,G1 会进行多次 Mixed GC:

  • 回收 Old 区中存活对象比例低的 Region
  • 同时进行新生代收集
  • 逐步回收老年代垃圾

四、G1 的关键技术

Remembered Set

用于记录跨代引用,避免全堆扫描:

  • 每个 Region 有一个 Remembered Set
  • 记录其他 Region 指向本 Region 的引用
  • 新生代收集时只需扫描 Remembered Set

SATB(Snapshot-At-The-Beginning)

确保并发标记的准确性:

  • 在标记开始时创建对象图的快照
  • 并发阶段新增的对象视为存活
  • 并发阶段删除的对象需要特殊处理

停顿预测模型

G1 使用统计模型预测回收时间:

  • 根据历史回收数据预测每个 Region 的回收时间
  • 选择回收时间总和不超过目标停顿时间的 Region
  • 动态调整回收策略

五、G1 的调优参数

基本参数

参数说明默认值
-XX:+UseG1GC启用 G1 回收器Java 9+ 默认
-Xms初始堆大小物理内存的 1/64
-Xmx最大堆大小物理内存的 1/4
-XX:MaxGCPauseMillis最大停顿时间目标200ms

高级参数

参数说明默认值
-XX:G1HeapRegionSizeRegion 大小自动计算
-XX:InitiatingHeapOccupancyPercent触发并发标记的堆占用率45%
-XX:G1NewSizePercent新生代最小比例5%
-XX:G1MaxNewSizePercent新生代最大比例60%
-XX:ParallelGCThreads并行回收线程数CPU 核心数
-XX:ConcGCThreads并发标记线程数CPU 核心数的 1/4

六、JVM 调优实战

调优步骤

  1. 监控 GC 状态:使用 jstat、jconsole 等工具
  2. 分析 GC 日志:使用 GCViewer、GCEasy 等工具
  3. 调整堆大小:根据应用需求设置合适的堆大小
  4. 调整新生代比例:根据对象存活时间调整
  5. 设置停顿时间目标:根据应用响应时间要求设置
  6. 优化代码:减少对象创建、避免内存泄漏

GC 日志分析

// 启用 GC 日志
java -Xms2G -Xmx2G -XX:+UseG1GC -XX:+PrintGCDetails -XX:+PrintGCTimeStamps -Xloggc:gc.log MyApp

日志解读

2.314: [GC pause (G1 Evacuation Pause) (young), 0.0230250 secs]
   [Parallel Time: 20.4 ms, GC Workers: 8]
   [GC Worker Start (ms): Min: 2314.0, Avg: 2314.1, Max: 2314.2, Diff: 0.2]
   [Ext Root Scanning (ms): Min: 0.1, Avg: 0.2, Max: 0.4, Diff: 0.3, Sum: 1.3]
   [Update RS (ms): Min: 0.5, Avg: 0.7, Max: 1.0, Diff: 0.5, Sum: 5.4]
   [Process Buffers (ms): Min: 0.0, Avg: 0.0, Max: 0.0, Diff: 0.0, Sum: 0.0]
   [Scan RS (ms): Min: 0.1, Avg: 0.2, Max: 0.3, Diff: 0.2, Sum: 1.2]
   [Code Root Scanning (ms): Min: 0.0, Avg: 0.0, Max: 0.0, Diff: 0.0, Sum: 0.0]
   [Object Copy (ms): Min: 16.6, Avg: 17.0, Max: 17.4, Diff: 0.8, Sum: 135.7]
   [Termination (ms): Min: 0.0, Avg: 0.1, Max: 0.2, Diff: 0.2, Sum: 0.6]
   [GC Worker End (ms): Min: 2334.4, Avg: 2334.5, Max: 2334.5, Diff: 0.1]
   [Code Root Fixup: 0.0 ms]
   [Code Root Purge: 0.0 ms]
   [Clear CT: 0.1 ms]
   [Other: 2.5 ms]
   [Choose CSet: 0.0 ms]
   [Ref Proc: 0.6 ms]
   [Ref Enq: 0.0 ms]
   [Redirty Cards: 0.2 ms]
   [Humongous Register: 0.0 ms]
   [Humongous Reclaim: 0.0 ms]
   [Free CSet: 0.2 ms]
   [Eden: 512.0M(512.0M)->0.0B(512.0M) Survivors: 64.0M->64.0M Heap: 678.5M(2048.0M)->166.5M(2048.0M)]

常见问题与解决方案

问题原因解决方案
频繁 Full GC老年代空间不足增大堆内存、减少大对象创建
停顿时间过长堆内存过大或 Region 过多调整 MaxGCPauseMillis、减小堆大小
内存碎片CMS 回收器的问题切换到 G1 回收器
Young GC 频繁新生代空间过小增大新生代比例
Concurrent Mode FailureCMS 回收速度跟不上切换到 G1 或 ZGC

七、总结

G1 回收器是现代 JVM 的核心组件:

  1. 内存布局:基于 Region 分区,支持灵活的内存管理
  2. 工作流程:新生代收集 + 并发标记 + Mixed GC
  3. 关键技术:Remembered Set、SATB、停顿预测模型
  4. 调优参数:控制堆大小、停顿时间、线程数等

调优建议

  • 优先使用 G1 回收器(Java 9+ 默认)
  • 根据应用需求设置合理的停顿时间目标
  • 监控 GC 状态,及时调整参数
  • 优化代码,减少不必要的对象创建

理解 G1 的工作原理和调优方法,对于保证应用程序的性能和稳定性至关重要。

© 版权声明
THE END
喜欢就支持一下吧
点赞12
相关推荐
评论 抢沙发

请登录后发表评论

    请登录后查看评论内容

温馨提示:
1、本内容转载于网络,版权归原作者所有!
2、本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
3、本内容若侵犯到你的版权利益,请联系我们,会尽快给予删除处理!