java诊断工具之jstack

star2017 1年前 ⋅ 358 阅读

简介

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 >&amp;2 "Usage: jstackSeries  [ count [ delay ] ]"
    echo >&amp;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
本文为博主原创文章,未经博主允许不得转载。
更多内容请访问:IT源点

相关文章推荐

全部评论: 0

    我有话说: