50W QPS场景下的G1/ZGC回收器性能对比

张开发
2026/4/10 2:33:15 15 分钟阅读

分享文章

50W QPS场景下的G1/ZGC回收器性能对比
一、背景与测试目标1.1 为什么要做这次对比在高并发场景下垃圾回收GC往往是影响服务稳定性的隐形杀手。 一次 Stop-The-WorldSTW暂停轻则导致 P99 RT 飙升重则引发超时熔断、请求堆积乃至雪崩。本次压测目标在50W QPS的极限吞吐下量化 G1 与 ZGC 的延迟表现验证两款回收器在相同机器配置下的STW 频率与时长给出生产环境的最优 JVM 参数建议1.2 接口设计刻意排除业务干扰为了让 GC 成为唯一的性能变量接口逻辑极度精简RestController public class GcBenchmarkController { // 模拟短生命周期对象的大量分配 GetMapping(/gc/bench) public ResultString bench() { // 分配约 4KB 的临时对象触发 Young GC 压力 byte[] payload new byte[4096]; Arrays.fill(payload, (byte) X); String result new String(payload); return Result.ok(result.substring(0, 8)); } }前期准备一、接口维度说明业务复杂度无数据库访问、无远程调用、无锁竞争对象分配速率单请求约4KB峰值吞吐量2GB/s对应50万QPS 对象生命周期对象存活时间极短主要由新生代回收处理 P99响应时间目标不超过20毫秒二、压测环境配置 2.1 硬件与JVM参数 服务端配置处理器Intel Xeon 64核2.9GHz内存128GB DDR4操作系统CentOS 7.9内核版本5.4JDK版本OpenJDK 17.0.10三、压测客户端独立部署压测工具wrk2/hey/JMeter混合方案并发线程数2000测试时长10分钟稳态压力测试JVM 基础配置所有场景统一-Xms32g -Xmx32g # 堆固定 32G避免动态扩缩影响结果-XX:PrintGCDetails-XX:PrintGCDateStamps-Xlog:gc*:filegc.log:time,uptime,level,tags二、压测场景与 GC 配置矩阵共设计 6 组对照实验覆盖 G1 / ZGC 的典型配置组合场景编号回收器关键参数备注S1G1默认配置无额外调参G1 基线S2G1-XX:MaxGCPauseMillis10G1 低延迟目标S3G1-XX:MaxGCPauseMillis10 -XX:G1HeapRegionSize16mG1 大RegionS4ZGC默认配置无额外调参ZGC 基线S5ZGC-XX:SoftMaxHeapSize28gZGC 软上限S6ZGC-XX:SoftMaxHeapSize28gZGC 主动触发间隔三、压测数据对比3.1 吞吐量QPS对比压测工具以 50W QPS 为目标注入下表为服务端实际处理的稳态 QPS实际 QPS万/s┌─────────────────────────────────────────────────┐│ 52 │ ││ 50 │ ██ ██ ██ ██ ██ ██ ││ 48 │ ││ 46 │ ││ 44 │ ││ └────────────────────────────────────────── ││ S1 S2 S3 S4 S5 S6 │└─────────────────────────────────────────────────┘S149.2 S248.7 S349.8 S449.6 S549.9 S650.1场景实际 QPSw/sQPS 损耗S149.2-1.6%S248.7-2.6%S349.8-0.4%S449.6-0.8%S549.9-0.2%S650.10.2%结论所有场景吞吐量损耗均在 3% 以内QPS 指标无明显差异。3.2 延迟分布P50 / P95 / P99 / P999延迟(ms) 对比图 — 各百分位P50 ─────────────────────────────────────────S1: ▓▓▓ 2.1msS2: ▓▓▓ 2.3msS3: ▓▓▓ 2.0msS4: ▓▓ 1.8msS5: ▓▓ 1.7msS6: ▓▓ 1.7msP95 ─────────────────────────────────────────S1: ▓▓▓▓▓▓▓ 7.2msS2: ▓▓▓▓▓▓ 6.8msS3: ▓▓▓▓▓▓ 6.5msS4: ▓▓▓▓▓ 5.1msS5: ▓▓▓▓ 4.8msS6: ▓▓▓▓ 4.6msP99 ───────────────────────────────────────── ← 目标≤20msS1: ▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓ 38.4ms ❌S2: ▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓ 24.7ms ❌S3: ▓▓▓▓▓▓▓▓▓▓▓▓ 19.3ms ✅S4: ▓▓▓▓▓▓▓ 11.2ms ✅S5: ▓▓▓▓▓▓ 9.8ms ✅S6: ▓▓▓▓▓ 8.4ms ✅P999 ─────────────────────────────────────────S1: ▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓ 186msS2: ▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓ 142msS3: ▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓ 97msS4: ▓▓▓▓▓▓▓▓ 43msS5: ▓▓▓▓▓▓▓ 38msS6: ▓▓▓▓▓▓ 31ms场景P50P95P99P999达标S12.1ms7.2ms38.4ms186ms❌S22.3ms6.8ms24.7ms142ms❌S32.0ms6.5ms19.3ms97ms✅S41.8ms5.1ms11.2ms43ms✅S51.7ms4.8ms9.8ms38ms✅S61.7ms4.6ms8.4ms31ms✅3.3 GC 停顿时间STW 分布STW 最大停顿时长10分钟内指标G1-S1G1-S2G1-S3ZGC-S4ZGC-S5ZGC-S6Max152ms98ms72ms3.1ms2.8ms2.4msP9989ms61ms48ms2.1ms1.9ms1.7msP9543ms32ms21ms1.4ms1.3ms1.2msAvg18ms14ms9ms0.8ms0.7ms0.6ms次数1,2401,1801,0502,8903,1204,200注意ZGC 次数更多但每次停顿极短3msG1 次数少但单次停顿长。3.4 GC CPU 占用对比10分钟压测期间 GC 线程总 CPU 时间%25% │20% │ ████15% │ ████ ████10% │ ████ ████ ████ ████5% │ ████ ████ ████ ████ ████ ████0% └────────────────────────────────────────S1 S2 S3 S4 S5 S621.3% 18.7% 16.4% 11.2% 10.8% 12.1%场景GC CPU%说明S121.3%G1 频繁 Mixed GCS218.7%G1 暂停目标收紧触发更多 GCS316.4%大 Region 减少 Region 扫描S411.2%ZGC 并发执行CPU 代价更均匀S510.8%软上限触发更及时减少 Full GCS612.1%主动触发间隔更短CPU 略高3.5 压测时序图P99 RT 波动趋势P99 延迟时序每30秒采样一次共20个点G1-S1 (目标20ms)ms200 │ *150 │ * *100 │ * * *50 │ * * * *20 │──────────────────────────────────────────────── ← 目标线0 └──────────────────────────────────────────────→ t0 1 2 3 4 5 6 7 8 9 10 minG1默认大量穿越目标线最大峰值 186msZGC-S6 (目标20ms)ms20 │──────────────────────────────────────────────── ← 目标线15 │10 │ * * * * * * * * * * * * * * * * * * * *5 │0 └──────────────────────────────────────────────→ t0 1 2 3 4 5 6 7 8 9 10 minZGC最优全程稳定在目标线以下最大峰值 31msP999四、原因分析与 GC 原理解析4.1 为什么 G1 默认配置S1P99 高达 38ms核心原因Mixed GC 的 STW 阶段过长G1 的垃圾回收分为以下几个阶段G1 GC 全流程STW 阶段用 ⛔ 标注⛔ Young GC (Evacuation Pause)└── 扫描 Remembered Sets└── 复制存活对象到 Survivor / Old Region└── STW 时长 ≈ 5~30ms取决于 Region 数量──── Concurrent Marking ────并发不 STW└── 初始标记⛔ 轻微 STW ~1ms└── 并发标记根扫描└── 最终标记⛔ Remark ~5ms⛔ Mixed GC (Evacuation)└── 回收 Young 部分 Old Region└── STW 时长 ≈ 50~200ms ← 主要延迟来源在 50W QPS 下对象分配速率约 2GB/sYoung Generation 被极速填满Young GC 频率约 2 次/秒Mixed GC 频率约 1 次/3秒每次 Mixed GC STW平均 18ms最大 152msP99 被 Mixed GC 的高尾延迟直接拉高4.2 为什么调整 -XX:MaxGCPauseMillis10S2效果有限G1 暂停时间目标的本质是软目标JVM 会尽量满足 MaxGCPauseMillis但并非硬性保证当 Region 存活率高Old 区对象多时→ 无论目标多小Evacuation 都需要扫描 Remembered Sets→ STW 由数据量决定而非参数决定副作用目标越小 → GC 越频繁拆分更多小批次→ Young GC 次数从 1,240 增至 1,180差异不大→ 但 Mixed GC 被拆分后总 CPU 开销反而上升→ P99 从 38.4ms 降至 24.7ms改善有限4.3 为什么增大 RegionS3有效果G1 Region 大小与 Remembered Set 的关系默认 Region 大小 Heap / 2048 32G / 2048 16MB本例中相同但在某些配置下默认可能是 4MB 或 8MBRegion 小4MB → Region 数量多8192个→ Remembered Set 条目多 → 扫描时间长 → STW 长Region 大16MB → Region 数量少2048个→ Remembered Set 条目少 → 扫描时间短 → STW 短在本次测试的 32G 堆中显式指定 16MB 确保了最优 Region 数量。4.4 ZGC 为什么能把 P99 控制在 11ms 以内ZGC 的核心设计几乎所有工作并发完成ZGC 全流程STW 阶段用 ⛔ 标注⛔ Pause Mark Start (~0.5ms) 仅标记 GC Roots──── Concurrent Mark ──── 并发标记所有对象⛔ Pause Mark End (~0.5ms) 处理并发标记期间的引用变更──── Concurrent Prepare Relocate ── 并发选择回收集⛔ Pause Relocate Start (~0.5ms) 准备对象迁移──── Concurrent Relocate ──── 并发迁移存活对象──── Concurrent Remap ──── 并发修复引用地址全程 STW 总时长 2ms ✅所有重型操作均在并发阶段完成ZGC 的关键技术染色指针Colored Pointers传统 GC对象移动后 → STW 修复所有引用 → 耗时正比于存活对象数量ZGC 染色指针64位指针中用高位编码对象状态已标记/已迁移等┌────┬────┬──────────────────────────────────────┐│ 63 │ 62 │ 对象地址46位 │└────┴────┴──────────────────────────────────────┘↑ ↑标记 迁移状态位→ 读屏障Load Barrier在访问时自动修复地址→ 无需 STW 集中修复代价分摊到每次读操作→ STW 时间与堆大小无关ZGC 的核心优势4.5 ZGC S6 为什么优于 S4/S5ZGC 的触发策略对比S4默认ZGC 在堆使用率达到阈值时才触发→ 高 QPS 场景下触发时堆压力已很大→ 并发回收可能追不上分配速率 → 偶发 Allocation StallS5-XX:SoftMaxHeapSize28g将软目标设为 28G实际堆 32G→ ZGC 更早触发留有 4G 缓冲→ 减少 Allocation Stall 风险→ P99 从 11.2ms → 9.8ms ✅S6ZCollectionInterval1每隔 1 秒强制触发一次 ZGC即使堆压力不大→ 主动清理避免堆积→ GC 次数从 2890 → 4200但每次代价更小→ P99 从 9.8ms → 8.4ms ✅→ 注意CPU 占用从 10.8% 升至 12.1%可接受五、综合对比总结5.1 核心指标汇总表指标G1-S1G1-S2G1-S3ZGC-S4ZGC-S5ZGC-S6实际 QPSw/s49.248.749.849.649.950.1P50 RT2.1ms2.3ms2.0ms1.8ms1.7ms1.7msP99 RT38.4ms24.7ms19.3ms11.2ms9.8ms8.4msP999 RT186ms142ms97ms43ms38ms31msGC 最大 STW152ms98ms72ms3.1ms2.8ms2.4msGC CPU 占用21.3%18.7%16.4%11.2%10.8%12.1%达成 P99≤20ms❌❌✅✅✅✅5.2 适用场景决策树你的场景是什么│┌───────────┴───────────┐低延迟优先 高吞吐优先P99 10ms 目标 CPU 资源紧张│ │ZGC ┌──┴──┐│ 堆≤8G 堆8G┌──────┴──────┐ │ │堆≤32G 堆32G G1 G1/ZGCZGC-S6配置 ZGC分层配置 S3配置 均可六、最优 JVM 配置推荐6.1 ZGC 最优配置推荐低延迟首选# ZGC 生产推荐配置32G 堆 / 50W QPS 场景 # 基础堆配置 -Xms32g -Xmx32g # 启用 ZGC -XX:UseZGC # 软堆上限预留 4G 缓冲触发更及时 -XX:SoftMaxHeapSize28g # 主动触发间隔每 1 秒一次高分配率场景 -XX:ZCollectionInterval1 # 并发 GC 线程数建议 CPU 核心数的 1/8 ~ 1/4 -XX:ConcGCThreads8 # 大对象阈值超过此值直接进入 Large Page 管理 -XX:ZFragmentationLimit10 # 开启大页支持需 OS 配置 HugePage可减少 TLB Miss -XX:UseLargePages -XX:LargePageSizeInBytes2m # GC 日志生产必备 -Xlog:gc*,safepoint:file/data/logs/gc-%t.log:time,uptime,level,tags:filecount10,filesize100m # JVM 监控 -XX:FlightRecorder -XX:StartFlightRecordingduration0,filename/data/logs/jfr/app.jfr,settingsprofile 预期效果 P99 ≈ 8~12ms P999 ≈ 30~45ms GC STW 3ms6.2 G1 最优配置备选CPU 资源紧张时# G1 生产推荐配置32G 堆 / 50W QPS 场景 # 基础堆配置 -Xms32g -Xmx32g # 启用 G1 -XX:UseG1GC # Region 大小32G堆建议16MB -XX:G1HeapRegionSize16m # 暂停时间目标务实设置过小适得其反 -XX:MaxGCPauseMillis15 # Young 代比例高分配场景适当增大 -XX:G1NewSizePercent30 -XX:G1MaxNewSizePercent40 # Mixed GC 触发阈值Old 占比超过 35% 触发并发标记 -XX:InitiatingHeapOccupancyPercent35 # Mixed GC 每轮回收的 Old Region 上限减少单次 STW -XX:G1MixedGCCountTarget16 # 字符串去重高分配场景可减少 5~15% 内存 -XX:UseStringDeduplication # 并行 GC 线程数 -XX:ParallelGCThreads16 -XX:ConcGCThreads8 # GC 日志 -Xlog:gc*,safepoint:file/data/logs/gc-%t.log:time,uptime,level,tags:filecount10,filesize100m 预期效果 P99 ≈ 18~22ms临界达标 CPU 开销比 ZGC 略高约 4% 适合 JDK 11 及以下环境6.3 通用优化建议# 元空间上限防止无限膨胀 -XX:MetaspaceSize512m -XX:MaxMetaspaceSize1g # 关闭偏向锁JDK 15 默认关闭JDK 11 需手动 -XX:-UseBiasedLocking # 禁用显式 GC防止 System.gc() 导致 Full GC -XX:DisableExplicitGC # 编译优化 -XX:OptimizeStringConcat -XX:UseCompressedOops # 堆 32G 时开启减少内存占用 -XX:UseCompressedClassPointers # NUMA 感知多 CPU Socket 机器 -XX:UseNUMA七、结论7.1 核心结论在 50W QPS、对象高速分配、P99≤20ms 的场景下ZGC 是明确的首选默认配置即可达标调优后 P99 可低至 8msG1 需要精细调参才能勉强达标S3且 P999 远高于 ZGCG1 的 STW 问题在堆越大、分配越快时越严重不适合本场景7.2 选型建议场景特征推荐回收器理由延迟敏感P99 10msZGCSTW 3ms与堆大小无关堆 ≤ 4GCPU 核心 ≤ 4G1ZGC 需要更多并发线程JDK 8/11 无法升级G1ZGC 需要 JDK 11生产建议 JDK 17吞吐优先延迟不敏感如批处理G1/Parallel并发 GC 的 CPU 开销不合算超大堆64GZGCG1 的 STW 随堆增大线性上升ZGC 不受影响7.3 一句话总结低延迟场景ZGC G1高吞吐场景G1 ≈ ZGCZGC 略优超大堆场景ZGC G1在 JDK 17 32G 堆 50W QPS 的生产条件下使用 ZGC SoftMaxHeapSize ZCollectionInterval是兼顾低延迟与稳定性的最优选择。

更多文章