目录
[一、生产 JVM 调优前置知识(必须掌握)](#一、生产 JVM 调优前置知识(必须掌握))
[1. 核心调优指标(生产看这 4 个就够)](#1. 核心调优指标(生产看这 4 个就够))
[2. 必备监控工具(生产标配)](#2. 必备监控工具(生产标配))
[3. 核心 JVM 参数(生产常用,无废话)](#3. 核心 JVM 参数(生产常用,无废话))
[二、标准生产调优流程(固定 5 步)](#二、标准生产调优流程(固定 5 步))
[三、4 个生产最典型的 JVM 调优实战案例](#三、4 个生产最典型的 JVM 调优实战案例)
[案例 1:YGC 频繁,但单次停顿短(高频小对象场景)](#案例 1:YGC 频繁,但单次停顿短(高频小对象场景))
[案例 2:频繁 FullGC,服务卡顿、超时(最危险场景)](#案例 2:频繁 FullGC,服务卡顿、超时(最危险场景))
[案例 3:大对象导致频繁 YGC+FGC(文件 / 图片 / 报文处理)](#案例 3:大对象导致频繁 YGC+FGC(文件 / 图片 / 报文处理))
[案例 4:G1GC 调优(JDK11 + 微服务通用场景)](#案例 4:G1GC 调优(JDK11 + 微服务通用场景))
[四、生产 JVM 参数最佳实践模板(直接复制用)](#四、生产 JVM 参数最佳实践模板(直接复制用))
[1. JDK8 低延迟服务(支付 / 电商)](#1. JDK8 低延迟服务(支付 / 电商))
[2. JDK11+ 微服务(通用最优)](#2. JDK11+ 微服务(通用最优))
[五、避坑指南(生产 90% 的人踩过)](#五、避坑指南(生产 90% 的人踩过))
JVM 调优核心目标:降低 GC 频率 / 停顿时间、避免 OOM、提升吞吐量、保证服务稳定 。生产环境调优一定遵循:监控定位 → 分析问题 → 参数调整 → 验证效果 闭环,绝不盲目加参数。
本文会用生产真实场景,从基础流程到 4 个典型实战案例,手把手讲透。
一、生产 JVM 调优前置知识(必须掌握)
1. 核心调优指标(生产看这 4 个就够)
- GC 停顿时间(STW):越短越好(电商 / 支付 < 200ms,日志 / 批处理可放宽)
- GC 频率 :YGC 尽量频繁但快,FGC/FullGC越少越好(最好 0)
- 内存使用率:老年代不持续上涨、无内存泄漏
- 吞吐量:用户代码执行时间 /(用户代码 + GC 时间),越高越好
2. 必备监控工具(生产标配)
- 实时查看:
jstat -gc PID 1000 10(最常用,看 GC 次数 / 耗时) - 内存 dump:
jmap -dump:format=b,file=heap.hprof PID(OOM 必用) - 日志分析:开启
-XX:+PrintGCDetailsGC 日志,用GCViewer/GCEasy分析 - 可视化:Arthas(阿里开源,生产首选,无侵入)、Prometheus+Grafana
3. 核心 JVM 参数(生产常用,无废话)
# 基础内存配置(必配)
-Xms4g # 初始堆 = 最大堆,避免扩容停顿,生产强制相等
-Xmx4g # 最大堆
-Xss1024k # 线程栈大小,默认1M足够,递归深可调大
-XX:MetaspaceSize=256m
-XX:MaxMetaspaceSize=512m
# GC算法(生产主流:JDK8用CMS,JDK11+用G1,ZGC)
-XX:+UseConcMarkSweepGC # JDK8 低延迟首选
-XX:+UseG1GC # JDK11+ 默认,平衡吞吐量/延迟
# GC日志(生产必须开启,排查问题救命用)
-Xloggc:/logs/gc.log
-XX:+PrintGCDetails
-XX:+PrintGCDateStamps
-XX:+UseGCLogFileRotation
-XX:GCLogFileSize=100M
# 异常保护(必配)
-XX:+HeapDumpOnOutOfMemoryError # OOM自动dump内存快照
-XX:HeapDumpPath=/logs/heap.hprof
二、标准生产调优流程(固定 5 步)
- 监控发现问题:YGC 频繁、FGC 不断、CPU 高、OOM
- 分析根因:内存泄漏?对象创建太快?堆太小?老年代囤积?
- 调整参数:只改 1-2 个参数,不一次性堆参数
- 压测 / 观察:观察 GC 指标变化
- 固化最优配置:稳定后保留参数,写入 Docker/K8s 启动脚本
三、4 个生产最典型的 JVM 调优实战案例
案例 1:YGC 频繁,但单次停顿短(高频小对象场景)
场景描述
- 微服务接口 QPS 高,大量创建局部对象(DTO、List、Map)
jstat显示:YGC 每 1-2 秒一次,每次 < 10ms,FGC 0- 服务无卡顿,但 GC 消耗 CPU 资源
根因
新生代(Eden+S 区)太小,对象快速占满 Eden,触发频繁 YGC。
调优方案
增大新生代空间,降低 YGC 频率:
# 原配置
-Xms2g -Xmx2g
# 调优后(新生代占堆 1/2,默认是 1/3)
-Xms2g -Xmx2g -Xmn1g
效果
YGC 频率从1 次 / 秒 → 1 次 / 10 秒,GC CPU 使用率下降,服务更稳定。
案例 2:频繁 FullGC,服务卡顿、超时(最危险场景)
场景描述
- 订单 / 支付核心服务,突然接口大量超时
jstat显示:FGC 几分钟一次,不断增长,单次停顿 500ms+- 堆内存:老年代持续 100% 占用
常见根因
- 内存泄漏(连接未关闭、静态集合缓存对象)
- 对象直接进入老年代(大对象 / 动态晋升)
- 老年代空间不足
排查步骤
- 导出堆 dump:
jmap -dump:format=b,file=oom.hprof PID - 用 MAT 工具分析:发现静态 Map 缓存了大量订单对象,未清理 → 内存泄漏
调优方案
-
代码修复:给缓存加过期时间、使用弱引用 / 本地缓存框架(Caffeine)
-
JVM 参数辅助:
增大堆,调整CMS触发阈值,提前回收
-Xms4g -Xmx4g
-XX:+UseConcMarkSweepGC
-XX:CMSInitiatingOccupancyFraction=70 # 老年代占70%触发CMS,避免满了再GC
-XX:+UseCMSInitiatingOccupancyOnly
效果
FGC 降为0 / 天,GC 停顿 < 100ms,服务无卡顿。
案例 3:大对象导致频繁 YGC+FGC(文件 / 图片 / 报文处理)
场景描述
- 服务处理 Excel 导入、大报文解析,创建几 MB 的大对象
- JVM 报错:
Preventing promotion of large object - YGC 和 FGC 同时频繁,OOM 频发
根因
大对象直接进入老年代,Eden 放不下,老年代快速被占满。
调优方案
-
代码优化:拆分大对象,流式处理,不一次性加载全量数据
-
JVM 参数:
1. 调大大对象阈值,让大对象优先在新生代分配
-XX:PretenureSizeThreshold=10m # >10M才直接进老年代
2. 增大新生代
-Xms4g -Xmx4g -Xmn2g
效果
大对象不再直接进入老年代,FGC 消失,OOM 解决。
案例 4:G1GC 调优(JDK11 + 微服务通用场景)
场景描述
- SpringCloud 微服务,JDK11,默认 G1GC
- 偶尔出现GC 停顿超过 300ms,接口超时
- 堆内存 4G,无内存泄漏
根因
G1 默认目标停顿200ms,未根据业务调整,混合回收效率低。
调优方案
G1 调优只改一个核心参数:期望停顿时间
-Xms4g -Xmx4g
-XX:+UseG1GC
-XX:MaxGCPauseMillis=100 # 目标停顿<100ms,G1自动调整分区大小
-XX:ConcGCThreads=4 # 根据CPU核心数调整
效果
GC 平均停顿 **<80ms**,无明显波动,服务稳定。
四、生产 JVM 参数最佳实践模板(直接复制用)
1. JDK8 低延迟服务(支付 / 电商)
JAVA_OPTS="
-Xms4g -Xmx4g -Xmn2g
-XX:MetaspaceSize=256m -XX:MaxMetaspaceSize=512m
-XX:+UseConcMarkSweepGC
-XX:CMSInitiatingOccupancyFraction=70
-XX:+UseCMSInitiatingOccupancyOnly
-Xloggc:/logs/gc.log
-XX:+PrintGCDetails -XX:+PrintGCDateStamps
-XX:+HeapDumpOnOutOfMemoryError
-XX:HeapDumpPath=/logs/
"
2. JDK11+ 微服务(通用最优)
JAVA_OPTS="
-Xms4g -Xmx4g
-XX:+UseG1GC
-XX:MaxGCPauseMillis=100
-XX:MetaspaceSize=256m -XX:MaxMetaspaceSize=512m
-Xlog:gc*:/logs/gc.log:time,level,tags
-XX:+HeapDumpOnOutOfMemoryError
-XX:HeapDumpPath=/logs/
"
五、避坑指南(生产 90% 的人踩过)
- 不要堆参数:一次只改 1 个参数,观察效果
- -Xms 必须等于 - Xmx:避免堆扩容导致的长时间停顿
- 不要无限加大堆:堆越大,FGC 停顿越长,4-8G 最均衡
- 先修代码,再调 JVM:内存泄漏、大对象靠调优解决不了
- 必须开 GC 日志和 OOM dump:出问题能快速定位
总结
- JVM 调优核心:先监控定位,再小步调整,不盲目操作
- 生产高频问题:YGC 频繁(加新生代)、FGC 频繁(内存泄漏 / 老年代不足)、大对象
- 最优方案:代码优化为主,JVM 参数为辅,配合 GC 日志 + Arthas 工具
- 直接可用:两套参数模板适配 JDK8/JDK11,覆盖绝大多数微服务场景