JDK 的 bin 目录下为 Java 开发人员提供了很多实用的小工具,很多场景下都会用到它们,比如:打包、部署、签名、调试、监控、运维等。本文介绍其中一款:
jstack (Stack Trace for Java): Java 堆栈跟踪工具
功能
生成虚拟机当前时刻的线程快照(一般称为 threaddump 或者 javacore 文件)。
线程快照就是当前虚拟机内每一条线程正在执行的方法堆栈的集合,生成线程快照的目的通常是定位线程出现长时间停顿的原因,如线程间死锁、死循环、请求外部资源导致的长时间挂起等,都是导致线程长时间停顿的常见原因。
线程出现停顿时通过 jstack 来查看各个线程的调用堆栈,就可以获知没有响应的线程到底在后台做些什么事情,或者等待着什么资源。
命令格式
1 | jstack [ option ] vmid |
option
选项 | 作用 |
---|---|
-F | 当正常输出的请求不被响应时,强制输出线程堆栈 |
-l | 除堆栈外,显示关于锁的附加信息 |
-m | 如果调用到本地方法的话,可以显示 C/C++ 的堆栈 |
执行样例
使用 jstack 查看线程堆栈
1 | $ jstack 5511 |
统计线程数
1 | $ jstack 5511 | grep 'java.lang.Thread.State' | wc -l |
使用 jstack 定位进程中 cpu 占用最高的线程
- 查看 cpu 占用高线程
-H: 指示 top 命令显示单个线程。如果没有该选项,则显示每个进程中的线程总和
-p: 后跟进程 ID (process id),这里为 LVMID
1 | $ top -H -p 5511 |
- 转换线程 ID
1 | $ printf "%x\n" 6072 |
- 定位进程中 cpu 占用最高的线程
-A: 往下展示 x 行信息
-B: 往上展示 x 行信息
加上 -A 或 -B,可以打印出线程具体的堆栈信息
1 | $ jstack 5511 | grep 17b8 -A 10 |
同理检测 cpu 高的原因
使用 top 命令找到 cpu 占用最高的进程
查看进程中 cpu 占用最高的线程(同上)寻找原因
reference: top
使用 jstack 检测死锁
- 死锁代码:
1 | import java.util.concurrent.TimeUnit; |
- demo 运行后 jps 查询 LVMID 为 33391:
1 | $ jps -l | grep DeathLockDemo |
- 使用 jstack 检测死锁
1 | $ jstack -l 33391 |
关键信息如下: