介绍

jstack用于生成java虚拟机当前时刻的线程快照。线程快照是当前java虚拟机内每一条线程正在执行的方法堆栈的集合,生成线程快照的主要目的是定位线程出现长时间停顿的原因,如线程间死锁、死循环、请求外部资源导致的长时间等待等。
线程出现停顿的时候通过jstack来查看各个线程的调用堆栈,就可以知道没有响应的线程到底在后台做什么事情,或者等待什么资源。

命令格式

root@cv-console-rds-68784cdf9c-zk4d8:/# jstack -help
Usage:
jstack [-l] <pid>
(to connect to running process)
jstack -F [-m] [-l] <pid>
(to connect to a hung process)
jstack [-m] [-l] <executable> <core>
(to connect to a core file)
jstack [-m] [-l] [server_id@]<remote server IP or hostname>
(to connect to a remote debug server)

Options:
-F to force a thread dump. Use when jstack <pid> does not respond (process is hung)
-m to print both java and native frames (mixed mode)
-l long listing. Prints additional information about locks
-h or -help to print this help message

-l参数

如果使用-l参数,除了方法栈帧以外,jstack命令还会显示关于锁的附加信息,比如属于java.util.concurrent的ownable synchronizers列表。

root@cv-console-rds-68784cdf9c-zk4d8:/# jstack -l 1
2022-05-06 11:13:21
Full thread dump OpenJDK 64-Bit Server VM (25.312-b07 mixed mode):

"clientOutboundChannel-65" #5189 prio=5 os_prio=0 tid=0x00007f9290006000 nid=0x1b64c waiting on condition [0x00007f92e98e7000]
java.lang.Thread.State: TIMED_WAITING (parking)
at sun.misc.Unsafe.park(Native Method)
- parking to wait for <0x00000000f6fc58b8> (a java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject)
at java.util.concurrent.locks.LockSupport.parkNanos(LockSupport.java:215)
at java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject.awaitNanos(AbstractQueuedSynchronizer.java:2078)
at java.util.concurrent.LinkedBlockingQueue.poll(LinkedBlockingQueue.java:467)
at java.util.concurrent.ThreadPoolExecutor.getTask(ThreadPoolExecutor.java:1073)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1134)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)
at java.lang.Thread.run(Thread.java:748)

Locked ownable synchronizers:
- None

"clientOutboundChannel-64" #5188 prio=5 os_prio=0 tid=0x00007f9290005000 nid=0x1b64b waiting on condition [0x00007f92ea1ea000]
java.lang.Thread.State: TIMED_WAITING (parking)
at sun.misc.Unsafe.park(Native Method)
- parking to wait for <0x00000000f6fc58b8> (a java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject)
at java.util.concurrent.locks.LockSupport.parkNanos(LockSupport.java:215)
at java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject.awaitNanos(AbstractQueuedSynchronizer.java:2078)
at java.util.concurrent.LinkedBlockingQueue.poll(LinkedBlockingQueue.java:467)
at java.util.concurrent.ThreadPoolExecutor.getTask(ThreadPoolExecutor.java:1073)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1134)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)
at java.lang.Thread.run(Thread.java:748)

Locked ownable synchronizers:
- None

"http-nio-31105-exec-18" #5074 daemon prio=5 os_prio=0 tid=0x00007f92c400f000 nid=0x1aae8 waiting on condition [0x00007f92e92e1000]
java.lang.Thread.State: TIMED_WAITING (parking)
at sun.misc.Unsafe.park(Native Method)
- parking to wait for <0x00000000f7e7e5d8> (a java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject)
at java.util.concurrent.locks.LockSupport.parkNanos(LockSupport.java:215)
at java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject.awaitNanos(AbstractQueuedSynchronizer.java:2078)
at java.util.concurrent.LinkedBlockingQueue.poll(LinkedBlockingQueue.java:467)
at org.apache.tomcat.util.threads.TaskQueue.poll(TaskQueue.java:89)
at org.apache.tomcat.util.threads.TaskQueue.poll(TaskQueue.java:33)
at java.util.concurrent.ThreadPoolExecutor.getTask(ThreadPoolExecutor.java:1073)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1134)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)
at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61)
at java.lang.Thread.run(Thread.java:748)

Locked ownable synchronizers:
- None

-m参数

如果使用-m参数,jstack命令将显示混合的栈帧信息,除了Java方法栈帧以外,还有本地方法栈帧。本地方法栈帧是C或C++编写的虚拟机代码或JNI/native代码。

root@cv-console-rds-68784cdf9c-zk4d8:/# jstack -m 1
Attaching to process ID 1, please wait...
Debugger attached successfully.
Server compiler detected.
JVM version is 25.312-b07
Deadlock Detection:

No deadlocks found.

----------------- 6 -----------------
0x00007f939b7587b2 __pthread_cond_wait + 0x1e2
----------------- 7 -----------------
0x00007f939b758ad8 __pthread_cond_timedwait + 0x238
----------------- 8 -----------------
0x00007f939b7587b2 __pthread_cond_wait + 0x1e2
----------------- 9 -----------------
0x00007f939b7587b2 __pthread_cond_wait + 0x1e2
----------------- 10 -----------------
0x00007f939b75b174 do_futex_wait.constprop.0 + 0x34
----------------- 11 -----------------
0x00007f939b758ad8 __pthread_cond_timedwait + 0x238
----------------- 12 -----------------
0x00007f939b758ad8 __pthread_cond_timedwait + 0x238
----------------- 13 -----------------
0x00007f939b7587b2 __pthread_cond_wait + 0x1e2
----------------- 14 -----------------
0x00007f939b758ad8 __pthread_cond_timedwait + 0x238
----------------- 25 -----------------
0x00007f939b758ad8 __pthread_cond_timedwait + 0x238
----------------- 26 -----------------
0x00007f939b7587b2 __pthread_cond_wait + 0x1e2
----------------- 93 -----------------
0x00007f939b758ad8 __pthread_cond_timedwait + 0x238
----------------- 94 -----------------
0x00007f939b7587b2 __pthread_cond_wait + 0x1e2
----------------- 95 -----------------
0x00007f939b758ad8 __pthread_cond_timedwait + 0x238
----------------- 96 -----------------
0x00007f939b7587b2 __pthread_cond_wait + 0x1e2
----------------- 103 -----------------
0x00007f939b758ad8 __pthread_cond_timedwait + 0x238
----------------- 110 -----------------
0x00007f939b7587b2 __pthread_cond_wait + 0x1e2
----------------- 111 -----------------
0x00007f939b758ad8 __pthread_cond_timedwait + 0x238
----------------- 112 -----------------
0x00007f939b758ad8 __pthread_cond_timedwait + 0x238
----------------- 149 -----------------
0x00007f939b758ad8 __pthread_cond_timedwait + 0x238
----------------- 181 -----------------
0x00007f939b758ad8 __pthread_cond_timedwait + 0x238
----------------- 182 -----------------
0x00007f939b758ad8 __pthread_cond_timedwait + 0x238
----------------- 189 -----------------
0x00007f939b758ad8 __pthread_cond_timedwait + 0x238
----------------- 190 -----------------
0x00007f939b7587b2 __pthread_cond_wait + 0x1e2
----------------- 191 -----------------
0x00007f939b758ad8 __pthread_cond_timedwait + 0x238
----------------- 205 -----------------
0x00007f939b465116 epoll_wait + 0x56
0x00007f938642aa32 <Unknown compiled code>
----------------- 206 -----------------
0x00007f939b7587b2 __pthread_cond_wait + 0x1e2
----------------- 207 -----------------
0x00007f939b7587b2 __pthread_cond_wait + 0x1e2
----------------- 208 -----------------
0x00007f939b758ad8 __pthread_cond_timedwait + 0x238
----------------- 209 -----------------
0x00007f939b758ad8 __pthread_cond_timedwait + 0x238
----------------- 210 -----------------
0x00007f939b758ad8 __pthread_cond_timedwait + 0x238
----------------- 211 -----------------
0x00007f939b7587b2 __pthread_cond_wait + 0x1e2
----------------- 212 -----------------
0x00007f939b465116 epoll_wait + 0x56
0x00007f938642aa32 <Unknown compiled code>
----------------- 213 -----------------
0x00007f939b7587b2 __pthread_cond_wait + 0x1e2
----------------- 216 -----------------
0x00007f939b465116 epoll_wait + 0x56
0x00007f938642aa32 <Unknown compiled code>
----------------- 218 -----------------
0x00007f939b758ad8 __pthread_cond_timedwait + 0x238
----------------- 219 -----------------
0x00007f939b758ad8 __pthread_cond_timedwait + 0x238
----------------- 220 -----------------
0x00007f939b758ad8 __pthread_cond_timedwait + 0x238
----------------- 221 -----------------
0x00007f939b758ad8 __pthread_cond_timedwait + 0x238
----------------- 222 -----------------
0x00007f939b758ad8 __pthread_cond_timedwait + 0x238
----------------- 223 -----------------
0x00007f939b758ad8 __pthread_cond_timedwait + 0x238
----------------- 224 -----------------
0x00007f939b758ad8 __pthread_cond_timedwait + 0x238
----------------- 225 -----------------
0x00007f939b758ad8 __pthread_cond_timedwait + 0x238
----------------- 226 -----------------
0x00007f939b758ad8 __pthread_cond_timedwait + 0x238
----------------- 227 -----------------
0x00007f939b465116 epoll_wait + 0x56
0x00007f938642aa32 <Unknown compiled code>
----------------- 228 -----------------
0x00007f939b75c1bf __libc_accept + 0x4f
0x00007f9386dc2f6a <Unknown compiled code>
----------------- 235 -----------------
0x00007f939b7587b2 __pthread_cond_wait + 0x1e2
----------------- 646 -----------------
0x00007f939b7587b2 __pthread_cond_wait + 0x1e2
----------------- 16973 -----------------
0x00007f939b758ad8 __pthread_cond_timedwait + 0x238
----------------- 16974 -----------------
0x00007f939b45a3ff __poll + 0x4f
0x00007f9384be2745 Java_java_net_SocketInputStream_socketRead0 + 0xe5
0x00007f938512eea1 <Unknown compiled code>
----------------- 16975 -----------------
0x00007f939b758ad8 __pthread_cond_timedwait + 0x238
----------------- 16976 -----------------
0x00007f939b7587b2 __pthread_cond_wait + 0x1e2
----------------- 17045 -----------------
0x00007f939b7587b2 __pthread_cond_wait + 0x1e2
----------------- 31525 -----------------
0x00007f939b75c1bf __libc_accept + 0x4f
0x00007f939a66c0bc _ZN14AttachListener7dequeueEv + 0xac
0x00007f939a66afc0 _ZL28attach_listener_thread_entryP10JavaThreadP6Thread + 0x1a0
0x00007f939add8c11 _ZN10JavaThread17thread_main_innerEv + 0xf1
0x00007f939ac859d2 _ZL10java_startP6Thread + 0x132
----------------- 101980 -----------------
0x00007f939b758ad8 __pthread_cond_timedwait + 0x238
----------------- 108911 -----------------
0x00007f939b758ad8 __pthread_cond_timedwait + 0x238
----------------- 108912 -----------------
0x00007f939b758ad8 __pthread_cond_timedwait + 0x238
----------------- 108913 -----------------
0x00007f939b758ad8 __pthread_cond_timedwait + 0x238
----------------- 108914 -----------------
0x00007f939b758ad8 __pthread_cond_timedwait + 0x238
----------------- 108915 -----------------
0x00007f939b758ad8 __pthread_cond_timedwait + 0x238
----------------- 108916 -----------------
0x00007f939b758ad8 __pthread_cond_timedwait + 0x238
----------------- 108935 -----------------
0x00007f939b758ad8 __pthread_cond_timedwait + 0x238
----------------- 109288 -----------------
0x00007f939b758ad8 __pthread_cond_timedwait + 0x238
----------------- 112203 -----------------
0x00007f939b758ad8 __pthread_cond_timedwait + 0x238
----------------- 112204 -----------------
0x00007f939b758ad8 __pthread_cond_timedwait + 0x238
----------------- 113392 -----------------
0x00007f939b758ad8 __pthread_cond_timedwait + 0x238
----------------- 113393 -----------------
0x00007f939b758ad8 __pthread_cond_timedwait + 0x238
----------------- 1 -----------------
0x00007f939b7534a7 __pthread_clockjoin_ex + 0x237
0x00007f939a208700 ????????
0x00007f939b53bf80 JLI_Launch + 0x9e0
0x000055e98320d836 main + 0x76

-F 参数

如果Java虚拟机进程由于进程挂起而没有任何响应,那么可以使用-F参数(仅在Oracle Solaris和Linux操作系统上游戏)强制显示线程快照信息。

root@cv-console-rds-68784cdf9c-zk4d8:/# jstack -F 1
Attaching to process ID 1, please wait...
Debugger attached successfully.
Server compiler detected.
JVM version is 25.312-b07
Deadlock Detection:

No deadlocks found.

Thread 113636: (state = BLOCKED)
- java.lang.Thread.sleep(long) @bci=0 (Compiled frame; information may be imprecise)
- sun.net.www.http.KeepAliveCache.run() @bci=3, line=172 (Interpreted frame)
- java.lang.Thread.run() @bci=11, line=748 (Compiled frame)


Thread 113591: (state = BLOCKED)
- sun.misc.Unsafe.park(boolean, long) @bci=0 (Compiled frame; information may be imprecise)
- java.util.concurrent.locks.LockSupport.parkNanos(java.lang.Object, long) @bci=20, line=215 (Compiled frame)
- java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject.awaitNanos(long) @bci=78, line=2078 (Compiled frame)
- java.util.concurrent.LinkedBlockingQueue.poll(long, java.util.concurrent.TimeUnit) @bci=62, line=467 (Compiled frame)
- java.util.concurrent.ThreadPoolExecutor.getTask() @bci=134, line=1073 (Compiled frame)
- java.util.concurrent.ThreadPoolExecutor.runWorker(java.util.concurrent.ThreadPoolExecutor$Worker) @bci=26, line=1134 (Compiled frame)
- java.util.concurrent.ThreadPoolExecutor$Worker.run() @bci=5, line=624 (Compiled frame)
- java.lang.Thread.run() @bci=11, line=748 (Compiled frame)


Thread 113590: (state = BLOCKED)
- sun.misc.Unsafe.park(boolean, long) @bci=0 (Compiled frame; information may be imprecise)
- java.util.concurrent.locks.LockSupport.parkNanos(java.lang.Object, long) @bci=20, line=215 (Compiled frame)
- java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject.awaitNanos(long) @bci=78, line=2078 (Compiled frame)
- java.util.concurrent.LinkedBlockingQueue.poll(long, java.util.concurrent.TimeUnit) @bci=62, line=467 (Compiled frame)
- java.util.concurrent.ThreadPoolExecutor.getTask() @bci=134, line=1073 (Compiled frame)
- java.util.concurrent.ThreadPoolExecutor.runWorker(java.util.concurrent.ThreadPoolExecutor$Worker) @bci=26, line=1134 (Compiled frame)
- java.util.concurrent.ThreadPoolExecutor$Worker.run() @bci=5, line=624 (Compiled frame)
- java.lang.Thread.run() @bci=11, line=748 (Compiled frame)


Thread 112204: (state = BLOCKED)
- sun.misc.Unsafe.park(boolean, long) @bci=0 (Compiled frame; information may be imprecise)
- java.util.concurrent.locks.LockSupport.parkNanos(java.lang.Object, long) @bci=20, line=215 (Compiled frame)
- java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject.awaitNanos(long) @bci=78, line=2078 (Compiled frame)
- java.util.concurrent.LinkedBlockingQueue.poll(long, java.util.concurrent.TimeUnit) @bci=62, line=467 (Compiled frame)
- java.util.concurrent.ThreadPoolExecutor.getTask() @bci=134, line=1073 (Compiled frame)
- java.util.concurrent.ThreadPoolExecutor.runWorker(java.util.concurrent.ThreadPoolExecutor$Worker) @bci=26, line=1134 (Compiled frame)
- java.util.concurrent.ThreadPoolExecutor$Worker.run() @bci=5, line=624 (Compiled frame)
- java.lang.Thread.run() @bci=11, line=748 (Compiled frame)

实践 -排查某个等待时间长的线程

# 匹配到xxxxxx内容+前5行+后5行
jstack -l 1 | grep -C 5 WAITING
# 匹配到xxxxxx内容+前5行
jstack -l 1 | grep -B 5 WAITING
# 匹配到xxxxxx内容+后5行
jstack -l 1 | grep -C 5 WAITING