java线上问题排查-Java 进程CPU高
常见原因:死循环 / 锁竞争 / 频繁GC / 大量计算
-
查看整体
进程
占用资源情况top
- 默认每 3 秒刷新一次
- 可按
P
排序(CPU 占用)或M
排序(内存占用) - 可改刷新间隔:
top -d 1 # 每秒刷新 top -c # 显示完整命令行
-
找到占用过高的 Java 进程,例如
pid=22714, 12406
-
列出 Java 进程信息
ps aux | grep java --color # 高亮显示 java 进程 jps # 显示 Java 进程及类名
Java 进程可能是某个线程导致高 CPU,需单独监控线程:
-
top 查看线程
top -H -p <pid> # 进程PID
-H
显示线程- 在 top 界面:
- 按大写
P
按 CPU 排序 - 按大写
M
按内存排序
- 按大写
- 示例:
top -p 22714 -H
- 其他查看线程命令:
ps -Lfp <pid> # 查看 pid 下所有线程 ps -mp <pid> -o THREAD,tid,time # 显示线程号、线程ID、CPU时间 ps -T -p <pid> # SID 列线程ID,CMD 列线程名
- 注意:
PR
表示优先级,值越小优先级越高THREAD
/tid
可用于后续堆栈分析
-
线程 ID 转十六进制
printf "%x\n" <tid> # tid线程 printf '0x%x' <tid>
- 示例:
printf "%x\n" 156643 # 输出 3d30 # 十六进制 线程号
-
查看线程堆栈
jstack <pid> | grep -a <hex_tid> jstack <pid> |grep hex_tid -A 30 -C5 –color jstack pid > 1.txt
用top出来的进程号,而不是top -H出来的线程号
- 示例:
jstack 22714 | grep -a 3d30
- 或直接查看整个线程堆栈:
jstack 22714 > thread.log
-
导出dump文件
-
导出
# 导出指定进程的完整堆快照(包含所有对象,无论是否存活) jmap -dump:format=b,file=<快照文件名>.dump <Java进程PID># 仅导出存活对象的堆快照(过滤已死亡对象,文件更小,推荐) jmap -dump:live,format=b,file=<快照文件名>.dump <Java进程PID>
参数 作用 format=b
指定快照格式为二进制(唯一支持格式,不可省略) file=<文件名>.dump
定义快照输出路径和文件名(建议包含时间戳,便于区分版本) live
可选参数,仅导出 “存活对象”(减少快照文件大小,避免无效数据干扰分析) <Java进程PID>
目标 Java 进程的 ID(通过 jps
或ps aux | grep java
获取) -
使用jdk自带的jvisualvm.exe分析快照
- “类” 标签页:查看对象数量与大小
- “实例” 标签页:查看具体对象详情
- “OQL 查询”:精准筛选对象
-
通过jhat命令生成html通过localhost:7000查看
# -J-Xmx2g 是给 jhat 自身分配堆内存(建议设为快照大小的 1.5 倍) jhat -J-Xmx2g <快照文件名>.dump # 解析 1GB 的快照,给 jhat 分配 2GB 堆内存 jhat -J-Xmx2g 20240520_myapp_heap.dump
注意:给线程起一个好名字非常重要,否则你刀磨的再快,命令玩儿的再溜,依然砍不到人。
-
-
分析dump文件
a. 死锁,Deadlock
b. 执行中,Runnable
c. 等待资源,Waiting on condition
d. 等待获取监视器,Waiting on monitor entry
e. 暂停,Suspended
f. 对象等待中,Object.wait()或TIMED_WAITING
g. 阻塞,Blocked
h. 停止,Parked
四、排查流程总结
top
或ps
→ 找到高 CPU Java 进程top -H -p <pid>
或ps -Lfp <pid>
→ 找到高 CPU 线程printf "%x\n" <tid>
→ 转线程 ID 为十六进制jstack <pid>
→ 查看线程堆栈- 分析代码、优化或修复
strace 命令
# 进程PID strace -o out.txt -p pid # 可以查看某pid的执行过程并记录到out.txt
💡 Tips
- 多次堆栈采样可确认是短暂峰值还是持续高 CPU
- 可以结合
perf
或async-profiler
做更深度分析