G1 垃圾回收器调优

背景和价值

image
https://javaguide.cn/java/jvm/memory-area.html#字符串常量池

G1 垃圾回收器(Garbage-First)采用了一种创新的 分区式堆内存布局(Region-Based Heap),完全不同于传统的连续分代模型。其核心设计通过动态划分和管理内存区域来实现高效回收与低停顿目标。以下是 G1 的 JVM 内存布局详解:


📊 1. 核心结构:Region(分区)

G1 将整个堆内存划分为 大小固定、数量可变 的独立内存块,称为 Region

  • Region 大小:默认为堆总大小除以 2048(范围 1MB~32MB,必须是 2 的幂),可通过 -XX:G1HeapRegionSize 手动设置。
    • 例如:堆大小 4GB → 默认 Region 大小 ≈ 2MB(4096MB ÷ 2048)。
  • Region 数量上限:最多 2048 个,因此最大支持堆内存为 64GB(32MB × 2048)。
  • 动态角色分配:每个 Region 在运行时被动态标记为以下类型之一,且角色可随 GC 过程变化:
Region 类型 用途 特点
Eden 存储新创建的对象 回收频率高,存活对象少时被快速清理
Survivor 存储从 Eden 区复制过来的存活对象(分为 S0、S1) 对象年龄增长,达到阈值后晋升至 Old 区
Old 存储长期存活的对象 回收成本高,通过 Mixed GC 部分回收
Humongous(英/hjuːˈmʌŋɡəs/) 存储 超过 Region 50% 大小 的大对象(如 >1MB 的数组) 避免大对象直接进入 Old 区导致碎片;跨多个 Region 存储超大对象

🔄 2. 逻辑分代与物理分离

  • 逻辑分代保留:G1 仍保留 年轻代(Eden + Survivor)老年代(Old) 的概念,但物理上不再连续。
  • 动态比例调整
    • 年轻代初始占比:堆的 5%(通过 -XX:G1NewSizePercent 设置)。
    • 年轻代最大占比:堆的 60%(通过 -XX:G1MaxNewSizePercent 限制)。
    • Eden/Survivor 比例:默认 8:1:1(例如 1000 个 Region 中,Eden 占 800 个,S0/S1 各占 100 个)。

⚙️ 3. 关键数据结构支持

(1) 卡表(Card Table)

  • 每个 Region 内部划分为 512 字节的卡(Card),记录跨 Region 引用关系。
  • 作用:加速并发标记阶段,避免全堆扫描。

(2) 回收优先级列表(Collection Set)

  • G1 后台维护 Region 回收价值排序列表,优先回收垃圾多、耗时少的 Region。
  • 回收策略:根据用户设置的 最大停顿时间-XX:MaxGCPauseMillis)动态选择回收范围。

🔄 4. 内存回收流程

G1 的回收过程基于 Region 分阶段进行:

  1. 年轻代回收(Young GC)

    • 仅回收 Eden + Survivor 区,存活对象复制到新 Survivor 或晋升至 Old 区。
    • STW(Stop-The-World) 但时间短(通常 <100ms)。
  2. 并发标记周期(Concurrent Marking)

    • 初始标记(STW):标记 GC Roots 直接引用对象。
    • 并发标记:与用户线程并行,标记存活对象。
    • 最终标记(STW):修正并发标记期间变动的引用。
    • 清理(STW):统计 Region 回收价值并排序。
  3. 混合回收(Mixed GC)

    • 回收所有年轻代 Region + 部分高价值老年代/Humongous Region
    • 触发条件:老年代占比 ≥ 阈值(默认 45%,通过 -XX:InitiatingHeapOccupancyPercent 设置)。
  4. Full GC(备用机制)

    • 当 Mixed GC 速度跟不上对象分配速率,或无足够空 Region 时触发。
    • 单线程 STW 整理,耗时较长(需尽量避免)。

💎 5. 设计优势与价值

特性 传统分代模型 G1 分区模型 优势
内存连续性 物理连续 逻辑连续,物理分散 避免内存碎片,长期运行更稳定
停顿预测 不可控 可设最大停顿时间(如 200ms) 满足 SLA 要求
大对象处理 直接进入老年代,引发碎片 专用 Humongous 区隔离存储 减少老年代压力,降低 Full GC 风险
回收效率 全代扫描 按 Region 价值优先级回收 有限时间内回收更多垃圾

总结
G1 的 Region 分区布局通过 物理分散、逻辑分代、动态角色分配 的设计,实现了内存碎片控制、停顿时间预测和大对象隔离三大核心价值。对于堆内存 ≥4GB 的应用,此布局能显著降低 Full GC 风险,尤其适合需要平衡吞吐量与延迟的服务器环境。

G1 参数调优

1 不要设置 -xmn来指定新生代堆内存,这种做法存在因为堆内存预估失败而导致的响应时间激增的问题。

-XX:G1NewSizePercent(新生代占用堆内存的最小比,默认为5%)以及-XX:G1MaxNewSizePercent(新生代占用堆内存的最大比,默认为60%)
新时代老年代占比。默认新时代占60%,如果应用有大量短期对象,可以适当增加年轻代的大小。

2 停顿时间。-XX:MaxGCPauseMillis 默认200ms,对响应时间敏感的应用(如 Web 应用、金融交易系统)可设置更低的值

3 Region大小设置。

RegionSize = MaxHeapSize (-Xmx) / 2048,结果取最接近的 2 的幂(范围 1MB~32MB)

🔍 二、何时需要调整 Region 大小?

1. 大对象(Humongous Object)频繁分配

  • 问题:对象 > RegionSize 的 50% 会被视为大对象(如 8GB 堆默认 4MB Region 下 >2MB 的对象)。
    • 大对象占用连续多个 Humongous Region,分配失败或回收效率低会导致 Full GC。
  • 解决策略
    • 若大对象频繁出现(如缓存、批量数据),增大 RegionSize(如 8GB 堆设 -XX:G1HeapRegionSize=8m),使大对象占比 ≤50%。
    • 监控依据:GC 日志中 humongous allocationto-space exhausted 警告。

⚠️ 一、警告类型及核心影响

警告类型 含义 根本原因
humongous allocation 对象大小 > RegionSize/2,被分配至老年代的 Humongous 区 - Humongous 对象过多导致老年代碎片化
- 频繁触发并发标记,中断 Mixed GC
to-space exhausted GC 复制阶段 Survivor 或老年代空间不足,存活对象无处迁移 - 疏散失败引发 Full GC(退化至 Serial GC)
- 堆碎片或预留空间不足

📊 二、何时需增大 Region 大小?

1. humongous allocation 警告频率阈值

  • 低风险(观察)
    ≤1 次/小时,且未触发 Full GC → 无需调整,监控即可。
  • 中风险(建议调整)
    ≥5 次/小时,或伴随 Old Gen 碎片率上升(GC 日志中 Old regions 持续增长) → 需增大 RegionSize。
  • 高风险(必须调整)
    警告频率 ≥1 次/分钟,或引发 Full GC(日志出现 Full GC (Allocation Failure)) → 立即增大 RegionSize 并优化关联参数

2. to-space exhausted 警告频率阈值

  • 低风险(观察)
    单次偶发,无 Full GC → 检查 -XX:G1ReservePercent(默认 10%)是否不足。
  • 中风险(建议调整)
    ≥2 次/天,或 Young GC 后 Old Gen 占用突增(对象被迫晋升) → 增大 RegionSize + 预留空间。
  • 高风险(必须调整)
    ≥1 次/小时,且触发 Full GC → 需同步调整 RegionSize 及混合回收策略。

Mixed GC 回收参数配置

-XX:InitiatingHeapOccupancyPercent

G1 垃圾回收器的 InitiatingHeapOccupancyPercent(简称 IHOP)是控制 ​Mixed GC 触发时机的核心参数,它定义了当老年代占堆内存的比例达到多少时启动并发标记周期(最终触发 Mixed GC)。默认值为 45%,但实际调优需结合应用的内存分配模式、延迟要求及堆规模动态调整。以下是综合调优建议及关联策略:

🔧 一、IHOP 参数的核心作用与默认风险

  • 机制:当老年代占用堆比例 ≥ IHOP 时,G1 启动并发标记,完成后触发 Mixed GC(回收年轻代 + 部分老年代)。
  • 默认值风险
    • 设值过低(如 <35%):过早触发 Mixed GC,频繁回收老年代,挤占业务线程 CPU,降低吞吐量。
    • 设值过高(如 >60%):延迟并发标记启动,可能引发老年代占满,触发 Full GC(单线程 STW,停顿秒级)。

⚖️ 二、调优场景与 IHOP 配置建议

1. 老年代增长快的场景(如缓存密集型应用)

  • 问题:对象快速晋升老年代,IHOP 默认值易导致堆占满。
  • 方案降低 IHOP(35%~40%),提前启动 Mixed GC:
    -XX:InitiatingHeapOccupancyPercent=35  # 主动预防 Full GC
    -XX:G1ReservePercent=15                # 预留空间防晋升失败
    -XX:G1MixedGCLiveThresholdPercent=70   # 扩大可回收老年代范围
    

    案例:某订单服务老年代占满触发 Full GC,IHOP 从 45% 降至 35% 后 Full GC 消失,最长停顿从 3s 降至 200ms。

2. 高并发低延迟场景(如实时交易系统)

  • 问题:Mixed GC 频繁中断业务线程,影响 P99 延迟。
  • 方案提高 IHOP(50%~70%),减少 Mixed GC 频率,优先保障年轻代回收:
    -XX:InitiatingHeapOccupancyPercent=70  
    -XX:MaxGCPauseMillis=500              # 放宽停顿目标
    -XX:G1NewSizePercent=40               # 扩大新生代缓冲突发流量
    

    案例:潮玩大促系统 IHOP 从 45% 调至 70%,Mixed GC 从 30 秒/次降至 5 分钟/次,Young GC 频率降低 20 倍。

3. 大堆内存场景(≥16GB)

  • 问题:老年代回收成本高,默认 IHOP 易导致碎片累积。
  • 方案中等 IHOP + 大 Region,平衡回收效率与碎片风险:
    -XX:InitiatingHeapOccupancyPercent=50  # 折中触发阈值
    -XX:G1HeapRegionSize=16m               # 减少碎片(16GB 堆)
    -XX:G1MixedGCCountTarget=16            # 分更多次回收,缩短单次停顿
    

⚠️ 三、关联参数协同调优

IHOP 需与以下参数配合,避免“头痛医头”:

  1. Mixed GC 回收效率

    • -XX:G1MixedGCLiveThresholdPercent(默认 85%):
      老年代 Region 存活对象占比 ≤ 此值时才回收。建议调低至 65%~70%,避免存活率高 Region 无法回收。
    • -XX:G1HeapWastePercent(默认 5%):
      堆可回收空间占比 ≥ 此值时触发 Mixed GC。碎片多时调高至 10%
  2. 新生代与内存预留

    • -XX:G1NewSizePercent/-XX:G1MaxNewSizePercent
      新生代占比范围(默认 5%~60%)。突发流量场景建议设 20%~40%,避免 Young GC 过频。
    • -XX:G1ReservePercent(默认 10%):
      预留堆空间防晋升失败。建议 10%~20%,大堆或大对象多时取高值。
  3. 线程与停顿控制

    • -XX:ConcGCThreads:并发标记线程数,建议 CPU 核数/4(如 16 核设 4)。
    • -XX:MaxGCPauseMillis:目标停顿时间,需 >Young GC 实际耗时(如 100~500ms),过低会迫使 G1 过度缩小新生代。

📊 四、分场景配置参考表

场景 IHOP 关联参数组合 调优目标
老年代增长快(缓存类) 35%~40% -XX:G1MixedGCLiveThresholdPercent=65
-XX:G1ReservePercent=15
预防 Full GC
高并发低延迟(交易类) 60%~70% -XX:G1NewSizePercent=40
-XX:MaxGCPauseMillis=300
减少 Mixed GC 干扰
大堆内存(≥16GB) 45%~55% -XX:G1HeapRegionSize=16m
-XX:G1MixedGCCountTarget=16
平衡回收效率与碎片风险
突发流量(大促活动) 40%~50% -XX:G1MaxNewSizePercent=50
-XX:G1ReservePercent=20
缓冲流量,避免晋升失败

-XX:+UseStringDeduplication

最近的一项研究表明,应用程序 13.5% 的内存中存在重复的字符串。当你传递 “-XX:+UseStringDeduplication” 参数时,G1 垃圾收集器(G1 GC)提供了一种消除重复字符串的选项。

以上大部分参数要根据实际业务压测。

参考资料

posted @ 2025-08-11 16:23  向着朝阳  阅读(135)  评论(0)    收藏  举报