Java 工具集教程

jstack.exe Java堆栈跟踪

jstack.exe 是 Java 虚拟机(JVM)自带的一种堆栈跟踪工具,它主要用于生成 Java 虚拟机当前时刻的线程快照。线程快照是当前 JVM 内每一条线程正在执行的方法堆栈的集合,生成线程快照的主要目的是定位线程出现长时间停顿的原因,如线程间死锁、死循环、请求外部资源导致的长时间等待等问题。

当 Java 程序出现长时间停顿或者无响应时,可以使用 jstack 命令来查看各个线程的调用堆栈,从而了解没有响应的线程到底在后台做什么事情,或者等待什么资源。此外,如果 Java 程序崩溃生成了 core 文件,jstack 工具也可以用来获取 core 文件的 Java stack 和 native stack 的信息,以助于诊断 Java 程序的崩溃原因和问题所在。

命令语法

连接正在运行的进程:

jstack [-l] <pid>

连接挂起的进程:

jstack -F [-m] [-l] <pid>

连接核心文件:

jstack [-m] [-l] <executable> <core>

连接远程调试服务器:

jstack [-m] [-l] [server_id@]<remote server IP or hostname>

参数说明:

  • option:可选参数,用于指定 jstack 命令的行为。

  • pid:需要打印堆栈信息的 Java 进程的进程 ID。

  • executable:产生 core dump 的 Java 可执行程序。

  • core:将被打印信息的 core dump 文件。

  • remote server IP or hostname:远程调试服务的主机名或 IP 地址。

  • server_id:唯一 ID,用于区分同一台主机上的多个远程调试服务。

命令选项

命令支持如下选项:

  • -F 强制线程转储。当 jstack <pid> 没有响应时使用(进程被挂起)

  • -m,同时打印 java 和本地框架(混合模式)

  • -l 长列表。打印有关锁的附加信息

  • -h 或 -help 用于打印帮助信息

命令示例

(1)打印某个进程的堆栈信息,如下:

D:\share_dir\ShareDoc> jstack 2256
2024-07-08 22:46:08
Full thread dump OpenJDK 64-Bit Server VM (17.0.6+10-b829.9 mixed mode):

Threads class SMR info:
_java_thread_list=0x0000018a745060e0, length=64, elements={
0x000001899fc74940, 0x00000189c81fc660, 0x00000189c81ff760, 0x00000189c8214400,
0x00000189c8c10940, 0x00000189c8c2a840, 0x00000189c8c2d110, 0x00000189c8c31200,
0x00000189c8c323d0, 0x00000189c8c49610, 0x00000189c8d680d0, 0x00000189c97f5bd0,
0x000001899fc756c0, 0x00000189f3a82010, 0x00000189f3ab3660, 0x00000189f3ab4000,
0x00000189f39e8010, 0x00000189f39e89b0, 0x00000189f39e6800, 0x00000189f39e7b40,
0x00000189f39e1630, 0x00000189f39e24a0, 0x00000189f39e5990, 0x00000189f39e2e40,
0x0000018a212d0560, 0x0000018a684c0a20, 0x0000018a6a129310, 0x0000018a72a08220,
0x0000018a72a0a3d0, 0x0000018a72a09560, 0x0000018a72a0a8a0, 0x0000018a6fb6f6c0,
0x00000189c94e9290, 0x0000018a74558620, 0x0000018a745611b0, 0x0000018a745671f0,
0x0000018a74568530, 0x0000018a75d3e320, 0x0000018aa6056740, 0x0000018aa60558d0,
0x0000018aa6058dc0, 0x0000018aa603dca0, 0x0000018aa60459c0, 0x0000018aa603f4b0,
0x0000018aa7a90c40, 0x0000018aa7a9b980, 0x00000189f3ab27f0, 0x00000189f3a829b0,
0x0000018a7455eb30, 0x0000018a7455b170, 0x0000018a75d404d0, 0x0000018a75d33ab0,
0x0000018aa6041660, 0x0000018aa603bfc0, 0x0000018a6fb73a20, 0x0000018a6fb790c0,
0x0000018aa7a82070, 0x00000189f39e3310, 0x00000189f39e1160, 0x0000018aa7ab6aa0,
0x0000018aa7aa49e0, 0x0000018aa7ab5290, 0x0000018aa7ab7440, 0x0000018a74564b70
}

"main" #1 prio=5 os_prio=0 cpu=2109.38ms elapsed=9952.72s tid=0x000001899fc74940 nid=0x2fc8 waiting on condition  [0x00000025756fe000]
   java.lang.Thread.State: TIMED_WAITING (parking)
    at jdk.internal.misc.Unsafe.park(java.base@17.0.6/Native Method)
    - parking to wait for  <0x00000000c2dc66e8> (a kotlinx.coroutines.BlockingCoroutine)
    at java.util.concurrent.locks.LockSupport.parkNanos(java.base@17.0.6/LockSupport.java:252)
    at kotlinx.coroutines.BlockingCoroutine.joinBlocking(Builders.kt:88)
    at kotlinx.coroutines.BuildersKt__BuildersKt.runBlocking(Builders.kt:59)
    at kotlinx.coroutines.BuildersKt.runBlocking(Unknown Source)
    at com.intellij.idea.Main.main(Main.kt:40)
...
"G1 Refine#1" os_prio=2 cpu=0.00ms elapsed=9950.28s tid=0x00000189f31cb170 nid=0x5cec runnable  

"G1 Service" os_prio=2 cpu=234.38ms elapsed=9952.72s tid=0x000001899fd13e20 nid=0x3c4c runnable  

"VM Periodic Task Thread" os_prio=2 cpu=406.25ms elapsed=9951.76s tid=0x00000189c93df610 nid=0x4c54 waiting on condition  

JNI global refs: 197, weak refs: 443

JNI global refs memory usage: 2739, weak refs: 13041

JNI global refs: 197, weak refs: 443

上面命令会打印出该进程的线程堆栈信息。

(2)强制打印无响应进程的堆栈信息

D:\share_dir\ShareDoc> jstack -F 21108
Attaching to process ID 21108, please wait...
Debugger attached successfully.
Server compiler detected.
JVM version is 25.45-b02
Deadlock Detection:

No deadlocks found.

Thread 37: (state = IN_NATIVE)
 - java.net.SocketInputStream.socketRead0(java.io.FileDescriptor, byte[], int, int, int) @bci=0 (Compiled frame; information may be imprecise)
 - java.net.SocketInputStream.socketRead(java.io.FileDescriptor, byte[], int, int, int) @bci=8, line=116 (Compiled frame)
 - java.net.SocketInputStream.read(byte[], int, int, int) @bci=79, line=170 (Compiled frame)
 - java.net.SocketInputStream.read(byte[], int, int) @bci=11, line=141 (Compiled frame)
 - java.io.BufferedInputStream.fill() @bci=214, line=246 (Compiled frame)
 - java.io.BufferedInputStream.read() @bci=12, line=265 (Compiled frame)
 - java.io.FilterInputStream.read() @bci=4, line=83 (Compiled frame)
 - sun.rmi.transport.tcp.TCPTransport.handleMessages(sun.rmi.transport.Connection, boolean) @bci=25, line=550 (Compiled frame)
 - sun.rmi.transport.tcp.TCPTransport$ConnectionHandler.run0() @bci=685, line=826 (Interpreted frame)
 - sun.rmi.transport.tcp.TCPTransport$ConnectionHandler.lambda$run$254() @bci=1, line=683 (Interpreted frame)
 - sun.rmi.transport.tcp.TCPTransport$ConnectionHandler$$Lambda$274.run() @bci=4 (Interpreted frame)
 - java.security.AccessController.doPrivileged(java.security.PrivilegedAction, java.security.AccessControlContext) @bci=0 (Compiled frame)
 - sun.rmi.transport.tcp.TCPTransport$ConnectionHandler.run() @bci=58, line=682 (Interpreted frame)
 - java.util.concurrent.ThreadPoolExecutor.runWorker(java.util.concurrent.ThreadPoolExecutor$Worker) @bci=95, line=1142 (Interpreted frame)
 - java.util.concurrent.ThreadPoolExecutor$Worker.run() @bci=5, line=617 (Interpreted frame)
 - java.lang.Thread.run() @bci=11, line=745 (Interpreted frame)


Thread 36: (state = BLOCKED)
 - java.lang.Object.wait(long) @bci=0 (Compiled frame; information may be imprecise)
 - com.sun.jmx.remote.internal.ServerCommunicatorAdmin$Timeout.run() @bci=227, line=168 (Interpreted frame)
 - java.lang.Thread.run() @bci=11, line=745 (Interpreted frame)


Thread 1: (state = BLOCKED)
...

Thread 9: (state = BLOCKED)


Thread 8: (state = BLOCKED)
 - java.lang.Object.wait(long) @bci=0 (Compiled frame; information may be imprecise)
 - java.lang.ref.ReferenceQueue.remove(long) @bci=59, line=143 (Compiled frame)
 - java.lang.ref.ReferenceQueue.remove() @bci=2, line=164 (Compiled frame)
 - java.lang.ref.Finalizer$FinalizerThread.run() @bci=36, line=209 (Interpreted frame)


Thread 7: (state = BLOCKED)
 - java.lang.Object.wait(long) @bci=0 (Compiled frame; information may be imprecise)
 - java.lang.Object.wait() @bci=2, line=502 (Interpreted frame)
 - java.lang.ref.Reference$ReferenceHandler.run() @bci=36, line=157 (Interpreted frame)

上面命令使用 -F 选项强制打印堆栈信息。

(3)打印关于锁的附加信息,如下:

D:\share_dir\ShareDoc> jstack -l 2256
2024-07-08 22:42:07
Full thread dump OpenJDK 64-Bit Server VM (17.0.6+10-b829.9 mixed mode):

Threads class SMR info:
_java_thread_list=0x0000018ab8d79a40, length=63, elements={
0x000001899fc74940, 0x00000189c81fc660, 0x00000189c81ff760, 0x00000189c8214400,
0x00000189c8c10940, 0x00000189c8c2a840, 0x00000189c8c2d110, 0x00000189c8c31200,
0x00000189c8c323d0, 0x00000189c8c49610, 0x00000189c8d680d0, 0x00000189c97f5bd0,
0x000001899fc756c0, 0x00000189f3a82010, 0x00000189f3ab3660, 0x00000189f3ab4000,
0x00000189f39e8010, 0x00000189f39e89b0, 0x00000189f39e6800, 0x00000189f39e7b40,
0x00000189f39e1630, 0x00000189f39e24a0, 0x00000189f39e5990, 0x00000189f39e2e40,
0x0000018a212d0560, 0x0000018a684c0a20, 0x0000018a6a129310, 0x0000018a72a08220,
0x0000018a72a0a3d0, 0x0000018a72a09560, 0x0000018a72a0a8a0, 0x0000018a6fb6f6c0,
0x00000189c94e9290, 0x0000018a74558620, 0x0000018a745611b0, 0x0000018a745671f0,
0x0000018a74568530, 0x0000018a75d3e320, 0x0000018aa6056740, 0x0000018aa60558d0,
0x0000018aa6058dc0, 0x0000018aa603dca0, 0x0000018aa60459c0, 0x0000018aa603f4b0,
0x0000018aa7a90c40, 0x0000018aa7a9b980, 0x00000189f3ab27f0, 0x00000189f3a829b0,
0x0000018a7455eb30, 0x0000018a7455b170, 0x0000018a75d404d0, 0x0000018a75d33ab0,
0x0000018aa6041660, 0x0000018aa603bfc0, 0x0000018a6fb73a20, 0x0000018a6fb790c0,
0x0000018aa7a82070, 0x00000189f39e3310, 0x00000189f39e1160, 0x0000018a745646a0,
0x0000018a72a0b240, 0x0000018a72a13430, 0x0000018aa7ab6aa0
}

"main" #1 prio=5 os_prio=0 cpu=2109.38ms elapsed=9711.61s tid=0x000001899fc74940 nid=0x2fc8 waiting on condition  [0x00000025756fe000]
   java.lang.Thread.State: TIMED_WAITING (parking)
    at jdk.internal.misc.Unsafe.park(java.base@17.0.6/Native Method)
    - parking to wait for  <0x00000000c2dc66e8> (a kotlinx.coroutines.BlockingCoroutine)
    at java.util.concurrent.locks.LockSupport.parkNanos(java.base@17.0.6/LockSupport.java:252)
    at kotlinx.coroutines.BlockingCoroutine.joinBlocking(Builders.kt:88)
    at kotlinx.coroutines.BuildersKt__BuildersKt.runBlocking(Builders.kt:59)
    at kotlinx.coroutines.BuildersKt.runBlocking(Unknown Source)
    at com.intellij.idea.Main.main(Main.kt:40)

   Locked ownable synchronizers:
    - None

...

"VM Thread" os_prio=2 cpu=765.62ms elapsed=9711.57s tid=0x00000189c81d5630 nid=0x5434 runnable  

"GC Thread#0" os_prio=2 cpu=2531.25ms elapsed=9711.61s tid=0x000001899fcb0270 nid=0x5224 runnable  

"GC Thread#1" os_prio=2 cpu=2296.88ms elapsed=9710.88s tid=0x00000189c8f40ed0 nid=0x5b08 runnable  

"GC Thread#2" os_prio=2 cpu=2531.25ms elapsed=9710.88s tid=0x00000189c9155340 nid=0x4bd8 runnable  

"GC Thread#3" os_prio=2 cpu=2843.75ms elapsed=9710.88s tid=0x00000189c9277ca0 nid=0x410c runnable  

"G1 Main Marker" os_prio=2 cpu=46.88ms elapsed=9711.61s tid=0x000001899fcb9950 nid=0x3a90 runnable  

"G1 Conc#0" os_prio=2 cpu=22375.00ms elapsed=9711.61s tid=0x000001899fcba480 nid=0xabc runnable  

"G1 Refine#0" os_prio=2 cpu=203.12ms elapsed=9711.61s tid=0x000001899fd13400 nid=0x31d8 runnable  

"G1 Refine#1" os_prio=2 cpu=0.00ms elapsed=9709.17s tid=0x00000189f31cb170 nid=0x5cec runnable  

"G1 Service" os_prio=2 cpu=218.75ms elapsed=9711.61s tid=0x000001899fd13e20 nid=0x3c4c runnable  

"VM Periodic Task Thread" os_prio=2 cpu=406.25ms elapsed=9710.66s tid=0x00000189c93df610 nid=0x4c54 waiting on condition  

JNI global refs: 197, weak refs: 443

JNI global refs memory usage: 2739, weak refs: 13041

JNI global refs: 197, weak refs: 443

上面例子使用 -l 选项可以打印出关于锁的附加信息,这有助于诊断死锁等问题。

说说我的看法
全部评论(
没有评论
关于
本网站专注于 Java、数据库(MySQL、Oracle)、Linux、软件架构及大数据等多领域技术知识分享。涵盖丰富的原创与精选技术文章,助力技术传播与交流。无论是技术新手渴望入门,还是资深开发者寻求进阶,这里都能为您提供深度见解与实用经验,让复杂编码变得轻松易懂,携手共赴技术提升新高度。如有侵权,请来信告知:hxstrive@outlook.com
公众号