排查java服务cpu高、内存泄漏、gc频繁、死锁时,应优先使用jdk自带命令行工具:jps定位pid,jstat监控gc与堆内存,jstack抓取线程栈分析死锁与阻塞,jmap生成堆快照或对象统计排查泄漏,jinfo动态查看和修改jvm参数。

排查线上Java服务CPU飙升、内存泄漏或GC频繁时,你得立刻知道哪个进程在作祟、堆里谁占了最多空间、线程卡在哪——这些全靠JDK自带的命令行工具现场抓取,不用装第三方软件,开箱即用。
查Java进程:jps快速定位目标PID
第一步:打开终端(Windows用CMD/PowerShell,Mac/Linux用Terminal),直接输入:
jps
这会列出当前所有Java进程的PID和主类简名,比如Jps是jps自身,Application是你跑的服务主类。
第二步:如果服务名重复或看不清启动参数,加-l输出完整类名或Jar路径:
jps -l
第三步:要确认某进程是否带了特定启动参数(比如-Dspring.profiles.active=prod),必须用-v:
jps -v
【注意:-v参数必须单独使用,不能和-q/-m混用,否则报错】
看堆内存和GC情况:jstat实时盯梢
方法一:只查一次堆各区域使用率(百分比)
jstat -gcutil 【PID】
输出里S0、S1、E、O、P五列分别代表两个Survivor区、Eden区、老年代、元空间的已用占比,O列超95%就该警惕内存泄漏。
方法二:每2秒刷新一次GC统计,持续10次
jstat -gc 【PID】 2s 10
重点关注YGCT(年轻代GC耗时总和)和FGCT(老年代GC耗时总和),若FGCT增长快于YGCT,说明对象晋升过多,可能触发频繁Full GC。
方法三:查堆容量配置上限
jstat -gccapacity 【PID】
NGCMX、OGCMX、PGCMX三列分别对应新生代、老年代、元空间的最大容量,和jinfo -flags 【PID】输出的-XX:MaxNewSize等参数交叉验证,能发现是否人为调小了堆导致GC压力激增。
抓线程快照分析死锁和阻塞
运行以下命令将当前Java进程的全部线程栈导出到文件:
jstack -l 【PID】 > thread_dump.log
打开thread_dump.log,搜索deadlock关键字,如果有匹配结果,说明存在死锁;没有则继续搜BLOCKED或WAITING状态的线程,重点看它们在等待哪个锁对象。
若需对比两次快照差异(比如CPU飙升前后),用以下命令连续抓3份,间隔5秒:
jstack -l 【PID】 > dump1.log && sleep 5 && jstack -l 【PID】 > dump2.log && sleep 5 && jstack -l 【PID】 > dump3.log
分析内存泄漏:jmap生成堆转储
方法一:直接导出存活对象的类统计表
jmap -histo:live 【PID】
输出按实例数降序排列,前三行通常是char[]、java.lang.String、java.util.HashMap——如果某业务类排进前十且实例数异常高,就是泄漏嫌疑对象。
方法二:生成完整堆快照供离线分析
jmap -dump:format=b,file=heap.hprof 【PID】
生成的heap.hprof文件较大,可用VisualVM或JProfiler打开,筛选“Dominator Tree”查看谁持有最多内存。
【关键前提:目标进程必须有读写权限,否则提示“Unable to open socket file”】
动态调参与信息提取:jinfo灵活干预
查看JVM启动时所有-XX参数:
jinfo -flags 【PID】
检查是否开启GC日志:若输出含-XX:+PrintGCDetails,则已启用;若没有,可临时追加:
jinfo -flag +PrintGCDetails 【PID】
设置堆转储路径(避免默认写入磁盘根目录):
jinfo -flag HeapDumpPath=/tmp/dumps 【PID】
执行后下次OOM自动在此路径生成heap.hprof文件。











