一、整体思路
JVM 性能监控分析分为事前配置埋点、事中实时监控、事后日志分析、故障快照定位 四层;先看内存走势、GC 频率、STW 停顿、线程状态、CPU 负载,再结合业务定位代码层、容器层、JVM 参数层瓶颈,从现象溯源根因,最终完成参数调优 + 代码优化落地。
核心思路:
监控采集 → 指标研判 → 故障定位 → 根因分析 → 分层优化 → 压测验证
优化优先级:业务代码优化 > JVM 参数调优 > 容器 / 系统内核优化 > 硬件升级
二、第一步:JVM 性能监控体系
1. 监控分层维度
- 应用层 :QPS、RT、错误率、接口并发、线程池状态
- JVM 层 :内存分区、GC、线程、编译、类加载、堆外内存
- 系统层 :CPU、内存、磁盘 IO、网络、负载、句柄数
- 容器层 :Docker 资源限制、CPU 核数、内存配额、OOM 杀手
2. 上线前监控预埋规范,JVM 日志参数统一配置
XML
# 打印GC时间、详情、日志输出
-XX:+PrintGCDetails
-XX:+PrintGCDateStamps
-XX:+PrintGCTimeStamps
-Xloggc:/data/logs/jvm/gc-%p.log
# OOM自动生成堆快照
-XX:+HeapDumpOnOutOfMemoryError
-XX:HeapDumpPath=/data/logs/jvm/heap-%p-%t.hprof
# 容器环境自动识别资源:监控类加载、内存溢出辅助
-XX:+TraceClassLoading
架构要点:生产日志按天切割、限制大小,避免磁盘打满。
3. 业务埋点
- 接口 RT、QPS、并发数、异步任务堆积
- 自定义埋点统计大对象创建、本地缓存数量监控
- 线程池活跃线程、队列积压监控
4. 中间件联动监控
Redis 连接数、DB 连接池、NIO 堆外内存使用量
三、第二层:命令行实时监控(JDK 命令行,线上应急排查必用)
1. jps:定位 Java 进程
jps -l
查看 Java 进程 PID,快速拿到PID,所有监控入口。
2. jstat : 实时 GC 与内存监控(最核心)(架构最常用)
XML
# 每500ms打印一次GC状态
jstat -gc PID 500
重点字段面试必说
S0/S1/E/O:新生代两区、伊甸区、老年代使用率。- S0U/S1U/EU/OU:实际已使用内存。
YGC/YGCT:新生代 GC 次数、总耗时。FGC/FGCT:FullGC 次数、总耗时。GCT:JVM 全局GC 耗时。
判断指标
- YGC 持续暴涨 → 短期对象疯狂创建
- FGC 持续上涨 → 内存泄漏 / 老年代满
- GCT 占业务耗时过高 → GC 停顿拖慢接口
3. jmap :堆内存查看 + 快照导出
XML
# 查看堆整体配置与使用:导出堆快照(流量低峰执行)
jmap -heap PID
# 导出线上堆快照(故障现场保留)
jmap -dump:format=b,file=heap.hprof PID
生产禁忌:流量高峰期禁止频繁 dump,会触发 STW 卡顿。
4. jstack:线程排查(线程死锁 / 阻塞 / CPU 飙升排查)
过滤死锁
jstack PID
jstack PID | grep deadlock
定位:
- 线程死锁
deadlock - 线程阻塞 BLOCKED
- 无限循环、死递归
- 线程池任务堆积
5. jinfo: 动态查看 / 修改 JVM 参数
jinfo -flags PID
查看当前生效所有 JVM 参数,核对线上配置是否生效。
6. 线上最强诊断:Arthas(架构师必备)
XML
# 启动
as.sh
# 常用核心命令
memory # 查看内存分区占用
gc # 实时GC监控
thread # 线程快照、死锁、高CPU线程;线程状态、阻塞、死锁
trace # 方法/接口耗时追踪
heapdump # 安全导出堆快照
dashboard # 全局面板监控
优势:无需重启、无强侵入、线上热诊断。
7. JDK 自带命令行工具链
- jps:查看所有 Java 进程
- jstat:实时监控 GC、类加载、编译统计
- jmap:堆内存快照、查看对象分布、dump 堆文件
- jstack:线程栈、死锁排查、CPU 飙升定位
- jinfo:实时查看 / 修改 JVM 参数
- jhat:字节码分析
- jcmd:全能综合命令
四、第三层:可视化平台监控(企业架构标配)
1. 主流监控体系
(1)服务监控:SkyWalking / Pinpoint / Prometheus+Grafana
1. SkyWalking / Pinpoint :全链路追踪 + JVM 指标一体化
2. Prometheus + Grafana :指标持久化、大屏看板、告警
3. VisualVM / JProfiler :本地深度性能剖析
4. MAT :堆快照内存泄漏专业分析
(2)告警体系:GC 次数告警、堆内存使用率告警、线程阻塞告警、OOM 告警
2. 核心监控指标(面试必背指标清单)
(1)内存指标
- 堆内存总使用率、Eden 区使用率、Survivor 使用率、老年代使用率
- 元空间 Metaspace 使用率
- 直接内存(堆外内存)占用
- 内存增长率(判断缓慢内存泄漏)
(2)GC 核心指标
- GC 频率、单次 YGC 平均耗时
- FullGC 次数、频率、单次停顿时长
- G1 专属:MixedGC 次数、分区回收耗时
- GC 吞吐量 = 业务运行时间 / (业务时间 + GC 时间)生产标准:吞吐量 > 95%
- STW 停顿时间:接口敏感业务控制在 200ms 以内
(3)线程指标
- 线程总数、新建线程速率
- 阻塞线程数、等待线程数、僵死线程
- 线程池核心线程、活跃线程、队列积压、拒绝次数
- 死锁线程检测
- 线程池队列积压数
- 虚拟线程数量(JDK21+)
(4)系统层指标
- CPU 使用率、用户态 / 内核态占比
- 磁盘 IO、网络流量、系统平均负载、磁盘读写压力、网络吞吐
3. 架构告警阈值(直接落地)
- 堆内存连续 5 分钟使用率>80% → 告警
- 1 分钟内 FullGC 次数 >2 → 紧急告警
- 单次 FullGC 停顿 >1s → 告警
- 元空间使用率>85% → 预警
- 业务线程阻塞数量突增 50% → 告警
- GC 吞吐量低于 90% → 性能降级告警
五、第四层:日志深度分析(GC 日志解读架构视角)
1. 区分 GC 类型
- Young GC:仅新生代回收,速度快
- Mixed GC:G1 混合回收部分新生代 + 部分老年代
- Full GC:整堆 + 元空间回收,STW 极长,线上高危
2. GC 日志分析判断瓶颈
- Eden 区迅速占满 → 接口产生大量临时对象
- Survivor 区存活对象过多 → 频繁晋升老年代
- Old 区缓慢持续上涨 → 内存泄漏实锤
- GC 后内存回收极少 → 存在大量常驻不可回收对象
- GC 频繁但回收量低 → 内存泄漏优先级最高
六、第五层:堆快照深度分析(MAT 架构分析法)
1. 分析工具
Eclipse MAT、JProfiler、IDEA 内置内存分析
2. 三步分析法
- 看大对象:找出占用内存 TOP10 对象
- 查泄漏引用链 :找出GC Roots 无法断开的常驻引用常见:静态集合、ThreadLocal 未清理、线程池持有业务对象、缓存无淘汰
- 分析对象数量:判断是单一大对象过多,还是批量小对象堆积
3. 高频泄漏定位点
- 未关闭连接池链接
- 全局 static 集合无限累加
- 异步线程 / 定时任务持有业务上下文
- 第三方框架内存常驻
- 堆外内存 DirectBuffer 泄漏
七、线上经典性能问题分析流程
1. 线上性能问题通用排查流程
业务接口卡顿 → 排查 CPU → 排查 GC → 排查线程阻塞 → 排查内存泄漏 → 定位代码层问题
场景 1:CPU 占用 100% 排查步骤
- top 找到高 CPU Java 进程 PID
- top -Hp PID 找到占用最高线程 ID
printf "%x 线程ID"转为十六进制- jstack PID | grep 十六进制 ID 精准定位代码行
- 常见根因:死循环、无限自旋、高频正则、死递归
场景 2:接口响应慢、RT 飙升
- 优先查看 GC 日志:是否频繁 YGC/FullGC、长时间 STW
- 查看线程状态:是否大量 BLOCKED 阻塞、锁竞争激烈
- 排查 IO 阻塞:DB 慢查询、Redis 阻塞、第三方接口超时
- 排查内存:老年代持续上涨即将 OOM
- 排查同步等待:synchronized、Lock 大量抢占
场景 3:服务内存持续上涨,久必 OOM
- jstat 持续观察:老年代只涨不降,回收极少
- 低峰期导出 heap.hprof 堆快照
- MAT 分析三步法
- 查看大对象排行
- 查找 GC Roots 不可断开引用链
- 定位常驻内存集合、未释放资源
- 高频泄漏点:ThreadLocal 未清理、静态集合无限累加、连接未关闭、堆外内存泄漏
场景 4:频繁 FullGC 服务卡顿
- 排除代码手动调用
System.gc() - 排查短期大对象批量创建直接进入老年代
- 排查内存泄漏导致老年代占满
- 查看 YGC 晋升失败、担保失败触发 FGC
- 核对新生代比例、对象晋升年龄配置
场景 5:容器内 JVM 性能异常
- 确认 JVM 是否识别容器内存 / CPU 限制
- 核对 - Xms -Xmx 的JVM 堆内存超过容器分配内存
- 避免宿主机内存挤压被系统 OOM-Killer 杀死进程
- 调整容器内存预留系统内存,防止内核内存耗尽
2 堆快照 MAT 深度分析实战
- 导入 hprof 文件,自动生成泄漏可疑报告
- 定位Leak Suspects可疑泄漏对象
- 查看对象实例数量、占用内存大小
- 追溯引用链,找到是谁持有对象无法被 GC 回收
- 区分:业务正常缓存 / 代码无意识内存泄漏
3 GC 日志深度解读
- 区分日志类型:YGC、MixedGC、FullGC
- 观察 GC 前后内存差值,判断回收效率
- 日志出现
concurrent mode failure:CMS 并发失败,退化为串行 FullGC - 日志出现
promotion failed:对象晋升失败,直接触发 FGC
八、JVM 分层性能优化实战
8.1 第一层:业务代码优化(效果最明显,优先做)
1)减少短命对象创建
- 循环体内禁止频繁 new 对象
- 字符串拼接优先
StringBuilder - 集合复用、全局统一对象池
- 批量查询分页处理,避免一次性加载海量数据
2)杜绝内存泄漏编码规范
- ThreadLocal 使用完毕必须 finally remove ()
- 数据库、Redis、文件、网络连接使用后强制 close
- 禁止使用 static List/Map 无限存储业务数据
- 本地缓存增加 LRU 淘汰、过期自动清理策略
- 异步线程、匿名内部类避免强持有外部业务对象
3)并发代码优化
- 缩小锁粒度,减少锁持有时间
- 多线程统一加锁顺序,杜绝死锁
- 读多写少场景使用读写锁
- 高并发计数使用
LongAdder替代 AtomicLong - 合理自定义线程池,设置队列上限与拒绝策略
4)减少 IO 阻塞耗时
- 数据库加索引、优化慢 SQL
- 热点数据前置缓存,减少 DB 查询
- 同步接口改异步、并行编排(CompletableFuture)
8.2 第二层:JVM 编译级优化(JIT 自动优化 + 手动开启)
1)逃逸分析优化(默认开启)
- 开启参数:
-XX:+DoEscapeAnalysis - 实现三大优化:栈上分配、标量替换、同步消除
- 让局部小对象直接分配栈内存,不进入堆,大幅降低 GC 压力
2)锁优化落地
- 高并发无偏向场景:关闭偏向锁
shell
-XX:-UseBiasedLocking
- 利用 JVM 自动锁粗化、锁消除减少锁竞争
- 业务层面拆分并行任务,降低锁冲突概率
3)热点代码优化
- 高频调用方法抽取通用工具类,提升 JIT 编译热度
- 减少冗余代码、空循环、无效判断,便于 C2 深度优化
8.3 第三层:内存与 GC 调优(生产核心)
1)通用最优内存配置原则
- 生产环境 -Xms = -Xmx 固定堆大小,禁止动态扩容缩容
- 线程栈统一设置
-Xss256k,减少内存占用、提升线程创建效率 - 元空间设置合理上下限,防止动态类无限膨胀
2)新生代调优
- 新生代占堆内存 1/3 ~ 1/4 最佳
- 短命对象多 → 适当调大新生代,减少晋升频率
- 调整
SurvivorRatio控制伊甸区与幸存区比例 - 合理调整晋升年龄
MaxTenuringThreshold
3)老年代调优
- 预留足够老年代空间,避免频繁装满触发 FGC
- 严控超大对象产生,避免直接进入老年代
- G1 调优:合理设置
MaxGCPauseMillis控制最大停顿
4)主流收集器生产配置模板
模板 1:微服务通用 → G1
shell
-Xms8g -Xmx8g -Xss256k
-XX:MetaspaceSize=256m
-XX:MaxMetaspaceSize=512m
-XX:+UseG1GC
-XX:MaxGCPauseMillis=200
-XX:+HeapDumpOnOutOfMemoryError
模板 2:金融高并发 / 低延迟 → ZGC(JDK21+)
shell
XML
-Xms16g -Xmx16g -Xss256k
-XX:+UseZGC
-XX:ZCollectionInterval=120
-XX:MetaspaceSize=512m
-XX:MaxMetaspaceSize=1g
模板 3:后台离线批量任务 → 吞吐量优先 Parallel
shell
XML
-Xms6g -Xmx6g
-XX:+UseParallelGC
-XX:ParallelGCThreads=8
8.4 第四层:容器 & 系统内核优化
- 调整系统最大文件句柄数
- 优化内核内存分配策略,减少 Swap 交换分区使用
- 容器 CPU 绑定核心,减少线程上下文切换
- 云原生环境开启大页内存,提升内存读写性能
8.5 第五层:新版本 JVM 特性优化
1)虚拟线程优化 IO 密集型业务
JDK21 + 虚拟线程替代传统线程池,百万级轻量线程,阻塞零开销,HTTP/DB/ 消息业务性能大幅提升。
2)分代 ZGC 优化大堆业务
年轻代高频低停顿回收,老年代低频回收,超大堆场景 GC 性能碾压 G1。
3)GraalVM AOT 提前编译
服务秒级启动、无预热、内存占用极低,适合 Serverless、轻量微服务。
8.6 JVM 性能优化避坑总结
- 不要盲目加大堆内存,堆越大 GC 单次停顿越长
- 不要随意修改高级 JVM 参数,默认参数经过官方极致优化
- 优先解决内存泄漏,再做 GC 参数调优
- 杜绝业务代码中手动触发 GC
- 调优完成必须经过压测验证,观察 GC 指标、RT、QPS 变化
九、性能优化验收标准
- 接口平均 RT 下降 30% 以上,无尖峰卡顿
- GC 吞吐量稳定 95% 以上,无频繁 FullGC
- 老年代内存走势平稳,无持续上涨
- 线程无大量阻塞、死锁、僵死现象
- 服务长时间压测稳定运行,无 OOM、无内存溢出
- 高峰期 CPU、内存资源使用率合理,无资源打爆
十、监控分析总结话术(面试背诵)
- 监控维度:从 JVM 内存、GC、线程、堆外内存、系统资源、业务 QPS 多维度联合监控,单一指标无法定位全貌。
- 分析顺序:先看 GC 吞吐量与停顿 → 再看内存占用趋势 → 排查线程状态 → 最后通过堆快照锁定代码层泄漏与对象创建问题。
- 优化优先级 :代码优化 > JVM 参数调优 > 硬件资源扩容,架构层面优先从业务减少短命对象、控制对象生命周期、合理使用缓存与线程池。
- 线上原则 :提前预埋日志与告警,做到故障提前预警、问题快速定位、根因彻底解决,杜绝只扩容不根治。
十一、极简面试背诵版
- 监控手段:命令行 (jps/jstat/jmap/jstack)、Arthas、SkyWalking、GC 日志、堆快照
- 核心观测:堆内存分区使用率、GC 频率、STW 停顿、线程状态、吞吐量
- 分析流程:现象观测 → 日志佐证 → 线程排查 → 堆快照溯源 → 代码 + 参数双优化
- 性能红线:FGC 严控、GC 吞吐量 95% 以上、单次 STW 控制业务容忍范围内
- 排查核心:绝大多数 JVM 性能问题,根源都是代码内存使用不合理,而非单纯参数问题。