问题描述
将 Spring Boot 微服务从 x86 迁移到鲲鹏 920(64 核 / 256GB 内存),功能测试通过,但压测发现 GC 停顿时间明显增大。x86 上平均 GC 停顿 30ms,鲲鹏上达到 80-120ms,偶尔出现 500ms 以上的长停顿,导致 P99 延迟波动。
排查过程
使用 G1 GC 日志分析停顿原因:
长停顿主要出现在 Young GC 和 Mixed GC 阶段。进一步用 jstat 观察堆内存分布:
第二步:调整 G1 GC 参数适配鲲鹏架构
关键参数说明:
G1HeapRegionSize=32m:匹配鲲鹏 64MB L3 缓存,减少跨 region 访问 UseNUMA:让 G1 感知 NUMA 拓扑,优先分配本地内存 ParallelGCThreads=16:设为单 NUMA 节点核数,避免跨节点调度 ConcGCThreads=8:并发标记线程数减半,降低 CPU 竞争
第三步:启用大页减少 TLB miss
效果验证
使用 JMH 压测并采集 GC 指标:
小结
鲲鹏上 Java GC 停顿大的根因是通用 OpenJDK 的 JIT 编译器和 G1 策略未针对 ARM 微架构优化。核心优化点:切换毕昇 JDK(针对鲲鹏优化)、启用 UseNUMA 感知拓扑、调整 G1HeapRegionSize 匹配缓存、开启大页。建议用 jstat -gcutil 监控元空间占用,用 GC 日志分析停顿分布,避免 Full GC 触发。
问题描述
将 Spring Boot 微服务从 x86 迁移到鲲鹏 920(64 核 / 256GB 内存),功能测试通过,但压测发现 GC 停顿时间明显增大。x86 上平均 GC 停顿 30ms,鲲鹏上达到 80-120ms,偶尔出现 500ms 以上的长停顿,导致 P99 延迟波动。
排查过程
使用 G1 GC 日志分析停顿原因:
# 添加 GC 日志参数后重启 java -Xms16g -Xmx16g \ -XX:+UseG1GC \ -XX:MaxGCPauseMillis=200 \ -Xlog:gc*:file=/var/log/app/gc.log:time,uptime,level,tags \ -jar app.jar # 分析 GC 日志 grep "Pause" /var/log/app/gc.log | tail -20 # 输出关键行: # [2024-01-15T10:23:45.123+0800] GC Pause Young (Normal) 120ms # [2024-01-15T10:23:52.456+0800] GC Pause Mixed 380ms # [2024-01-15T10:24:01.789+0800] GC Pause Young (Concurrent Start) 520ms <-- 长停顿长停顿主要出现在 Young GC 和 Mixed GC 阶段。进一步用
jstat观察堆内存分布:第二步:调整 G1 GC 参数适配鲲鹏架构
# 启动参数优化 java -Xms16g -Xmx16g \ -XX:+UseG1GC \ -XX:MaxGCPauseMillis=200 \ -XX:G1HeapRegionSize=32m \ -XX:+UseNUMA \ -XX:+UseLargePages \ -XX:ParallelGCThreads=16 \ -XX:ConcGCThreads=8 \ -Xlog:gc*:file=/var/log/app/gc.log:time,uptime,level,tags \ -jar app.jar关键参数说明:
G1HeapRegionSize=32m:匹配鲲鹏 64MB L3 缓存,减少跨 region 访问UseNUMA:让 G1 感知 NUMA 拓扑,优先分配本地内存ParallelGCThreads=16:设为单 NUMA 节点核数,避免跨节点调度ConcGCThreads=8:并发标记线程数减半,降低 CPU 竞争第三步:启用大页减少 TLB miss
效果验证
使用 JMH 压测并采集 GC 指标:
小结
鲲鹏上 Java GC 停顿大的根因是通用 OpenJDK 的 JIT 编译器和 G1 策略未针对 ARM 微架构优化。核心优化点:切换毕昇 JDK(针对鲲鹏优化)、启用
UseNUMA感知拓扑、调整G1HeapRegionSize匹配缓存、开启大页。建议用jstat -gcutil监控元空间占用,用 GC 日志分析停顿分布,避免 Full GC 触发。