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. 关键阶段
- 初始标记(Initial Mark) :短暂 STW,标记根对象。
- 并发标记(Concurrent Mark) :与应用线程并行。
- 最终标记(Final Mark) :短暂 STW,处理剩余引用。
- 并发回收(Concurrent Evacuation) :无 STW 移动对象,核心优势!🌟
- 引用处理(Reference Processing) :处理弱引用、软引用等。
- 并发压缩(Concurrent Compaction) :可选阶段,进一步减少碎片。
Shenandoah vs. G1:关键对比 🔄
| 特性 | Shenandoah | G1 |
|---|---|---|
| 设计目标 | 极致低延迟(亚毫秒级 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!🚀