jstack详解
jstack
详解:Java 线程转储分析与应用指南
jstack
是 JDK 自带的命令行工具,用于生成 Java 虚拟机(JVM)的线程快照(Thread Dump),帮助开发者诊断线程问题(如死锁、CPU 高负载等)。以下是详细说明:
1. 核心作用
- 生成线程转储:查看 JVM 内所有线程的调用栈、状态及锁信息。
- 诊断问题:分析线程阻塞、死锁、资源竞争、CPU 占用过高等场景。
2. 基本用法
jstack [options] <pid>
<pid>
:目标 Java 进程的 ID(通过jps
或ps -ef | grep java
获取)。- 常用选项:
-F
:强制生成转储(适用于 JVM 未响应)。-l
:显示锁的附加信息(如持有锁的线程、等待锁的线程)。-m
:混合模式输出(包括本地方法栈,如 JNI 调用)。
3. 线程转储内容解析
"main" #1 prio=5 os_prio=0 tid=0x00007f4874003000 nid=0x1ae4 runnable [0x00007f487c7e8000]
java.lang.Thread.State: RUNNABLE
at java.io.FileInputStream.readBytes(Native Method)
at java.io.FileInputStream.read(FileInputStream.java:255)
...
Locked ownable synchronizers:
- None
- 线程名称(如
"main"
)。 - 线程状态:
RUNNABLE
、BLOCKED
、WAITING
、TIMED_WAITING
。 - nid:系统级线程 ID(十六进制,对应
top -H -p <pid>
中的线程 ID)。 - 调用栈:线程当前执行的方法栈。
- 锁信息:持有的锁对象或等待的锁。
4. 应用场景与操作步骤
场景 1:检测死锁
- 步骤:
- 执行
jstack -l <pid>
。 - 搜索输出中的
deadlock
关键字,如:Found one Java-level deadlock: ... "Thread-1": waiting to lock monitor 0x00007f48ac0038b8 (object 0x000000076ac382c0, ...) which is held by "Thread-0"
- 执行
- 解读:明确列出死锁涉及的线程及资源,需检查代码的同步逻辑。
场景 2:分析高 CPU 线程
- 定位高 CPU 线程:
top -H -p <pid> # Linux 下找到占用高的线程 ID(十进制)。 printf "%x\n" <tid> # 转为十六进制(即 nid)。
- 匹配线程栈:
- 在
jstack
输出中搜索nid=<十六进制>
,分析该线程的调用栈。
- 在
场景 3:线程长时间阻塞
- 查找
WAITING
或TIMED_WAITING
状态的线程,结合堆栈判断原因:Object.wait()
:等待 notify 唤醒。LockSupport.park()
:可能因锁或并发工具类(如ReentrantLock
)阻塞。
5. 注意事项
- 权限限制:需使用启动 JVM 的同用户执行。
- 性能影响:短暂挂起所有线程,生产环境慎频繁调用。
- 工具结合:
jcmd
:替代部分功能(如jcmd <pid> Thread.print
生成转储)。- VisualVM/Arthas:图形化分析或动态诊断。
6. 示例:高 CPU 分析流程
# 查找 Java 进程 ID
jps -l
# 输出:12345 MyApp
# 查看进程的线程 CPU 占用
top -H -p 12345
# 输出:线程 6789 占用 90% CPU
# 转为十六进制(6789 → 0x1a85)
printf "%x\n" 6789 # 得到 1a85
# 生成线程转储并搜索 nid=0x1a85
jstack -l 12345 | grep -A 30 'nid=0x1a85'
总结:jstack
是 Java 应用性能调优和故障排查的核心工具,通过分析线程状态与堆栈,快速定位代码层面的并发问题。结合系统监控命令(如 top
)和后续的代码审查,可有效解决死锁、资源竞争或 CPU 过载等问题。