必须用jps -lv定位pid、jstat -gc监控gc频率、jstack -l抓线程栈查死锁、jmap -histo:live统计对象查泄漏,各命令参数错误会导致信息缺失或权限失败。

排查线上 Java 应用 CPU 飙高、内存泄漏或线程死锁时,必须快速定位进程 ID、查看 GC 频率、抓取线程栈和堆快照——这些操作全依赖 JDK 自带命令,缺一不可,且每个命令的参数选错会导致信息缺失或权限失败。
jps:快速定位 Java 进程 PID
第一步:执行 jps -lv,直接列出所有 Java 进程的 PID、主类全路径和完整 JVM 启动参数。
这一步能一眼识别出哪个进程是你的 Spring Boot 应用,而不是被 jps 自身或其他监控工具干扰。如果只用 jps,可能看到 Jps 或 Bootstrap 这类模糊名称,根本无法对应服务。
第二步:若输出为空但 ps -ef | grep java 能查到进程,说明 【/tmp/hsperfdata_$USER 目录缺失或无读权限】,此时 jps 失效,必须改用 ps -ef | grep -v grep | grep java | awk '{print $2}' 提取 PID。
jstat:实时监控 JVM 垃圾回收状态
方法一:查看当前 GC 概况,执行 jstat -gc <pid></pid>。输出字段中 YGC 是 Young GC 次数,FGC 是 Full GC 次数,数值突增就代表有内存压力。
方法二:每 1 秒刷新一次、持续 10 次,执行 jstat -gc <pid> 1000 10</pid>。注意单位是毫秒,写成 1 会误以为是 1 秒,实际是 1 毫秒——触发高频采样,可能压垮终端。
方法三:要直观看各代内存使用百分比,用 jstat -gcutil <pid></pid>。其中 E(Eden)、O(Old)、M(Metaspace)列的值超过 95%,基本可判定对应区域即将触发 GC 或已发生泄漏。
jstack:抓取线程快照分析阻塞与死锁
执行 jstack -l <pid> > thread_dump.log</pid>,将完整线程栈导出到文件。
这一步必须加 -l 参数,否则无法显示锁的详细信息(比如 java.util.concurrent.locks.ReentrantLock$NonfairSync),死锁检测会失效。导出后用文本编辑器搜索 deadlock,若存在,下面会明确列出互相持有和等待的线程 ID 及锁对象。
如果目标进程是容器内 Java 应用且提示 Unable to open socket file,说明容器未挂载 /tmp 或禁用了 Attach 机制,此时需在启动时添加 -XX:+StartAttachListener 参数。
jmap:检查堆内存与生成堆转储
① 查看堆内存结构:运行 jmap -heap <pid></pid>,重点关注 PSYoungGen 和 ParOldGen 的已用容量,以及 MaxMetaspaceSize 是否接近上限。
② 统计存活对象分布:执行 jmap -histo:live <pid> | head -20</pid>,输出前 20 行对象类型及实例数。若发现大量 byte[]、char[] 或业务实体类持续增长,就是内存泄漏的强信号。
③ 生成堆转储文件:运行 jmap -dump:format=b,file=heap.hprof <pid></pid>。该操作会触发 Full GC,【务必避开业务高峰期执行】,否则应用可能卡顿 10 秒以上。











