简介
jstack需要指定具体的进程,打印虚拟机里所有线程的堆栈跟踪信息,大概可以知道以下这些信息:java线程、虚拟机内部线程、本地堆栈帧、死锁检查。
所有线程的堆栈跟踪可用于诊断许多问题,比如死锁或挂起。
使用-l选项可以在堆栈中查看同步器的情况,并打印相关java.util.concurrent.locks信息,如果没有设置-l选项,那么只显示监视器上的一些信息,也可以使用thread.getAllStackTraces方法来获取Thread dumps,或在调试器中使用调试器选项打印所有线程堆栈。
如果发现系统出现问题,那么可以jstack多次,比较每次的堆栈信息是否相同,如果相同的话就可能死循环了。
强制stack dump
有时候存在挂起的进程,导致jstack pid没有响应,那么可以使用-F选项来解决,可以强制stack dump,可以看示例:
$ jstack -F 8321
Attaching to process ID 8321, please wait...
Debugger attached successfully.
Client compiler detected.
JVM version is 1.6.0-rc-b100
Deadlock Detection:
Found one Java-level deadlock:
=============================
"Thread2":
waiting to lock Monitor@0x000af398 (Object@0xf819aa10, a java/lang/String),
which is held by "Thread1"
"Thread1":
waiting to lock Monitor@0x000af400 (Object@0xf819aa48, a java/lang/String),
which is held by "Thread2"
Found a total of 1 deadlock.
Thread t@2: (state = BLOCKED)
Thread t@11: (state = BLOCKED)
- Deadlock$DeadlockMakerThread.run() @bci=108, line=32 (Interpreted frame)
Thread t@10: (state = BLOCKED)
- Deadlock$DeadlockMakerThread.run() @bci=108, line=32 (Interpreted frame)
Thread t@6: (state = BLOCKED)
Thread t@5: (state = BLOCKED)
- java.lang.Object.wait(long) @bci=-1107318896 (Interpreted frame)
- java.lang.Object.wait(long) @bci=0 (Interpreted frame)
- java.lang.ref.ReferenceQueue.remove(long) @bci=44, line=116 (Interpreted frame)
- java.lang.ref.ReferenceQueue.remove() @bci=2, line=132 (Interpreted frame)
- java.lang.ref.Finalizer$FinalizerThread.run() @bci=3, line=159 (Interpreted frame)
Thread t@4: (state = BLOCKED)
- java.lang.Object.wait(long) @bci=0 (Interpreted frame)
- java.lang.Object.wait(long) @bci=0 (Interpreted frame)
- java.lang.Object.wait() @bci=2, line=485 (Interpreted frame)
- java.lang.ref.Reference$ReferenceHandler.run() @bci=46, line=116 (Interpreted frame)
核心dump获取stack堆栈
为了获取核心dump的stack堆栈,可以从核心文件上执行jstack命令,如示例:
jstack $JAVA_HOME/bin/java core
注意:jdk12开始,可以使用jhsdb
命令查看核心dump文件
jhsdb jstack --exe java-home/bin/java --core core-file
混合stack
jstack还可以打印混合stack,也就是说,他除了打印java堆栈之外,还可以打印本地堆栈帧,本地帧是c/c++
编写的vm代码或JNI/native代码。打印混合stack可以使用-m参数,如示例:
$ jstack -m 21177
Attaching to process ID 21177, please wait...
Debugger attached successfully.
Client compiler detected.
JVM version is 1.6.0-rc-b100
Deadlock Detection:
Found one Java-level deadlock:
=============================
"Thread1":
waiting to lock Monitor@0x0005c750 (Object@0xd4405938, a java/lang/String),
which is held by "Thread2"
"Thread2":
waiting to lock Monitor@0x0005c6e8 (Object@0xd4405900, a java/lang/String),
which is held by "Thread1"
Found a total of 1 deadlock.
----------------- t@1 -----------------
0xff2c0fbc __lwp_wait + 0x4
0xff2bc9bc _thrp_join + 0x34
0xff2bcb28 thr_join + 0x10
0x00018a04 ContinueInNewThread + 0x30
0x00012480 main + 0xeb0
0x000111a0 _start + 0x108
----------------- t@2 -----------------
0xff2c1070 ___lwp_cond_wait + 0x4
0xfec03638 bool Monitor::wait(bool,long) + 0x420
0xfec9e2c8 bool Threads::destroy_vm() + 0xa4
0xfe93ad5c jni_DestroyJavaVM + 0x1bc
0x00013ac0 JavaMain + 0x1600
0xff2bfd9c _lwp_start
----------------- t@3 -----------------
0xff2c1070 ___lwp_cond_wait + 0x4
0xff2ac104 _lwp_cond_timedwait + 0x1c
0xfec034f4 bool Monitor::wait(bool,long) + 0x2dc
0xfece60bc void VMThread::loop() + 0x1b8
0xfe8b66a4 void VMThread::run() + 0x98
0xfec139f4 java_start + 0x118
0xff2bfd9c _lwp_start
----------------- t@4 -----------------
0xff2c1070 ___lwp_cond_wait + 0x4
0xfec195e8 void os::PlatformEvent::park() + 0xf0
0xfec88464 void ObjectMonitor::wait(long long,bool,Thread*) + 0x548
0xfe8cb974 void ObjectSynchronizer::wait(Handle,long long,Thread*) + 0x148
0xfe8cb508 JVM_MonitorWait + 0x29c
0xfc40e548 * java.lang.Object.wait(long) bci:0 (Interpreted frame)
0xfc40e4f4 * java.lang.Object.wait(long) bci:0 (Interpreted frame)
0xfc405a10 * java.lang.Object.wait() bci:2 line:485 (Interpreted frame)
... more lines removed here to reduce output...
----------------- t@12 -----------------
0xff2bfe3c __lwp_park + 0x10
0xfe9925e4 AttachOperation*AttachListener::dequeue() + 0x148
0xfe99115c void attach_listener_thread_entry(JavaThread*,Thread*) + 0x1fc
0xfec99ad8 void JavaThread::thread_main_inner() + 0x48
0xfec139f4 java_start + 0x118
0xff2bfd9c _lwp_start
----------------- t@13 -----------------
0xff2c1500 _door_return + 0xc
----------------- t@14 -----------------
0xff2c1500 _door_return + 0xc
以星号(*)前缀的帧是Java帧,而没有星号前缀的帧是原生的c/ c++
帧。
jstack可以通过管道c++filt
来把c++
混乱的符号名进行输出,因为Java HotSpot虚拟机是用c++
开发的,jstack为Java HotSpot内部函数打印c++
错误的符号名。
c++filt
实用程序是与本机c++
编译器套件一起交付的:Oracle Solaris操作系统上的SUNWspro和Linux上的gnu。
jstack相关选项
jstack [options] pid
jstack [options] executable core
jstack [options] [server-id@] remote-hostname-or-IP
options:命令行选项。
pid:打印堆栈的进程id,这个进程必须是java进程,可以用个jps获取机器上所有的java进行列表。
executable:生成核心dump的Java可执行文件。
core:要打印堆栈跟踪的核心文件。
remote-hostname-or-IP:远程调式服务器主机名或者ip地址。
server-id@:当多个调试服务器运行在同一个远程主机上时,可以使用一个可选的惟一ID。
options解释
-F:当jstack pid没有响应时强制进行堆栈dump。
-l:可以打印一些附加信息,如java.util.concurrent
的信息。如果使用了该配置,并且线程存在死锁,那么控制台会输出如下信息:
Locked ownable synchronizers: - <0x000000076c637cd0> (a java.util.concurrent.locks.ReentrantLock$NonfairSync)
如果不存在死锁,那么输出:
Locked ownable synchronizers: - None
-m:打印java和c++
混合的堆栈信息。
-h/-help:打印帮助信息。
输出到日志文件
可以把堆栈信息输出到具体的日志文件中,如
jstack pid >>xxx.log
已知问题
-m选项在debug远程服务的时候不起效果。
jstack工具只有jdk1.5之后才支持。
即使jvm参数中配置了-Xrs,jstack依旧可以使用。
jdk1.6中的jstack工具不能获取jdk1.5的堆栈dump。
脚本输出dump
#!/bin/bash
if [ $# -eq 0 ]; then
echo >&2 "Usage: jstackSeries [ count [ delay ] ]"
echo >&2 " Defaults: count = 10, delay = 1 (seconds)"
exit 1
fi
pid=$1 # required
count=${2:-10} # defaults to 10 times
delay=${3:-1} # defaults to 1 second
while [ $count -gt 0 ]
do
jstack $pid >jstack.$pid.$(date +%H%M%S.%N)
sleep $delay
let count--
echo -n "."
done
调用规则:脚本名称 pid 统计次数 延迟几秒
可以这样使用脚本:
jstackSeries 10 5
注意:本文归作者所有,未经作者允许,不得转载