Shenandoah GC 核心知识点 🚀

284 阅读3分钟

1. 设计目标

Shenandoah 是 低延迟垃圾收集器(Low-Pause GC),专注于减少 全局停顿时间(STW),尤其适合 大堆内存(几十GB到TB级)场景。其核心是通过 并发压缩(Concurrent Compaction)减少内存碎片,避免 Full GC。


2. 核心机制

  • 并发标记与回收

    • 并发标记:与应用程序线程并行标记存活对象。
    • 并发回收:在标记完成后,无需 STW 即可移动存活对象,释放空闲内存。
    • 转发指针(Brooks Pointer) :每个对象头存储一个指针,用于并发移动对象时快速重定向引用。🎯
  • 区域(Region)划分

    • 内存划分为固定大小的 Region(默认 2MB~32MB),类似 G1,但 无分代概念(Shenandoah 1.8 后支持分代模式)。
  • 写屏障(Write Barrier)

    • 通过 读屏障 + 写屏障 跟踪对象引用变化,确保并发移动时数据一致性。
    • 比 G1 的写屏障更轻量,减少运行时开销。⚡

3. 关键阶段

  1. 初始标记(Initial Mark) :短暂 STW,标记根对象。
  2. 并发标记(Concurrent Mark) :与应用线程并行。
  3. 最终标记(Final Mark) :短暂 STW,处理剩余引用。
  4. 并发回收(Concurrent Evacuation)无 STW 移动对象,核心优势!🌟
  5. 引用处理(Reference Processing) :处理弱引用、软引用等。
  6. 并发压缩(Concurrent Compaction) :可选阶段,进一步减少碎片。

Shenandoah vs. G1:关键对比 🔄

特性ShenandoahG1
设计目标极致低延迟(亚毫秒级 STW)平衡吞吐与延迟(百毫秒级 STW)
并发阶段并发标记、并发回收、并发压缩并发标记,回收阶段需 STW
内存布局固定大小 Region,可选分代动态大小 Region,分代(Young/Old)
压缩阶段完全并发并行压缩(需 STW)
内存开销略高(转发指针 + 屏障开销)较低
适用场景大堆 + 低延迟敏感(实时系统、游戏)中等堆 + 吞吐敏感(Web 服务)
JDK 支持JDK 12+ 正式支持JDK 7+ 主流支持

调优项与最佳实践 🛠️

1. 基础参数

bash

复制

-XX:+UseShenandoahGC                   # 启用 Shenandoah
-XX:ShenandoahGCHeuristics=adaptive    # 自适应启发式策略(默认)
-XX:ShenandoahGCMode=generational      # JDK 21+ 分代模式(可选)

2. 关键调优项

  • 并发线程数

    bash

    复制

    -XX:ConcGCThreads=<N>                 # 并发线程数(默认=CPU核数/4)
    
  • 触发阈值

    bash

    复制

    -XX:ShenandoahInitFreeThreshold=70    # 初始回收触发阈值(堆空闲百分比)
    -XX:ShenandoahMinFreeThreshold=10     # 最小回收触发阈值
    
  • Region 大小

    bash

    复制

    -XX:ShenandoahRegionSize=<size>       # 建议与 G1 的 Region 对齐(如 2MB/4MB)
    
  • 屏障优化

    bash

    复制

    -XX:+UseFastJNIAccessors              # 加速 JNI 访问
    -XX:-UseBiasedLocking                 # 禁用偏向锁(减少屏障冲突)
    

3. 监控与日志

bash

复制

-Xlog:gc*,safepoint,task*=info:file=gc.log  # 输出详细 GC 日志
-XX:+ShenandoahPrintHeapAtGC           # 打印堆状态(调试用)

4. 避坑指南 ⚠️

  • 避免过大堆:即使 Shenandoah 支持 TB 级堆,但建议根据业务需求分配合理内存。
  • 分代模式选择:JDK 21+ 分代模式适合短生命周期对象,但可能增加 CPU 开销。
  • 混合使用屏障:某些旧框架(如 Netty)可能因屏障导致性能下降,需测试验证。

总结 🌈

  • Shenandoah:适合追求极致低延迟的场景,通过 并发回收 减少 STW,但需牺牲少量吞吐和内存。
  • G1:更适合通用场景,平衡吞吐与延迟,成熟稳定。

根据业务需求选择,小堆选 G1,大堆高敏感选 Shenandoah!🚀