jstack
的基本用法jstack <pid> > threaddump.txt
打开 threaddump.txt 文件,可以查看所有线程的状态和调用栈信息。
如果 JVM 进程没有响应,可以使用 -F
选项强制生成线程转储文件:
jstack -F <pid> > threaddump.txt
使用-m
选项可以生成混合模式线程转储文件,包含 Java 和本地方法调用栈:
jstack -m <pid> > threaddump.txt
使用 -l
选项可以生成包含锁信息的线程转储文件:
jstack -l <pid> > threaddump.txt
线程转储文件通常包含以下部分:
每个线程的状态可能是以下几种之一:
RUNNABLE
:线程正在运行。BLOCKED
:线程被阻塞,等待获取锁。WAITING
:线程正在等待其他线程的通知。TIMED_WAITING
:线程正在等待,但有超时限制。TERMINATED
:线程已终止。每个线程的调用栈信息,显示了线程当前执行的方法和调用链。
如果使用了 -l
选项,线程转储文件会包含锁的持有者和等待者信息。
在线程转储文件中,查找 BLOCKED
状态的线程,并检查它们等待的锁。如果多个线程互相等待对方持有的锁,则可能存在死锁。
示例:
"Thread-1" #12 prio=5 os_prio=0 tid=0x00007f8b3810f800 nid=0x1e3 waiting for monitor entry [0x00007f8b2c7f0000]
java.lang.Thread.State: BLOCKED (on object monitor)
at com.example.DeadlockExample.methodB(DeadlockExample.java:20)
- waiting to lock <0x000000076b9c8c98> (a java.lang.Object)
at com.example.DeadlockExample.methodA(DeadlockExample.java:15)
- locked <0x000000076b9c8c88> (a java.lang.Object)
"Thread-2" #13 prio=5 os_prio=0 tid=0x00007f8b38110800 nid=0x1e4 waiting for monitor entry [0x00007f8b2c6ef000]
java.lang.Thread.State: BLOCKED (on object monitor)
at com.example.DeadlockExample.methodA(DeadlockExample.java:15)
- waiting to lock <0x000000076b9c8c88> (a java.lang.Object)
at com.example.DeadlockExample.methodB(DeadlockExample.java:20)
- locked <0x000000076b9c8c98> (a java.lang.Object)
在线程转储文件中,查找 RUNNABLE
状态的线程,并检查它们的调用栈,找出占用 CPU 的代码。
示例:
"Thread-0" #11 prio=5 os_prio=0 tid=0x00007f8b3810e800 nid=0x1e2 runnable [0x00007f8b2c8f1000]
java.lang.Thread.State: RUNNABLE
at com.example.CPUIntensiveTask.run(CPUIntensiveTask.java:10)
在线程转储文件中,查找 WAITING
或 TIMED_WAITING
状态的线程,并检查它们等待的条件或锁。
示例:
"Thread-3" #14 prio=5 os_prio=0 tid=0x00007f8b38111800 nid=0x1e5 waiting on condition [0x00007f8b2c5ee000]
java.lang.Thread.State: WAITING (parking)
at sun.misc.Unsafe.park(Native Method)
- parking to wait for <0x000000076b9c8ca8> (a java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject)
at java.util.concurrent.locks.LockSupport.park(LockSupport.java:175)
at java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject.await(AbstractQueuedSynchronizer.java:2039)
at com.example.BlockingExample.run(BlockingExample.java:15)
top
找到高 CPU 线程top -H -p <pid>
找到占用 CPU 最高的线程,将其线程 ID 转换为十六进制:
printf "%x\n" <thread_id>
生成线程转储文件,并在文件中查找对应的线程 ID:
jstack <pid> > threaddump.txt
grep <thread_id_in_hex> threaddump.txt
jstack 是分析 JVM 线程问题的重要工具,可以帮助定位死锁、线程阻塞、CPU 占用过高等问题。通过结合 top 和其他工具,可以更高效地分析线程状态和调用栈。