jstack用于打印出给定的java进程ID或core file或远程调试服务的Java堆栈信息,如果是在64位机器上,需要指定选项"-J-d64",Windows的jstack使用方式只支持以下的这种方式:
jstack [-l] pid
jstack [ option ] [server-id@]remote-hostname-or-IP
基本参数:
-F当’jstack [-l] pid’没有相应的时候强制打印栈信息
-l长列表. 打印关于锁的附加信息,例如属于java.util.concurrent的ownable synchronizers列表.
-m打印java和native c/c++框架的所有栈信息.
注意:-F参数 一般不要加,它是取当前挂起的线程信息,很多东西拿不到
注意:此命令会列出系统存在的死锁
- sudo jstack -F 27409 > data.txt
- sudo jstack -J-d64 -F 27409
输出:
- Deadlock Detection:
- No deadlocks found.
- Thread 2768: (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=226 (Compiled frame)
- - java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject.awaitNanos(long) @bci=68, line=2082 (Compiled frame)
- - java.util.concurrent.ArrayBlockingQueue.poll(long, java.util.concurrent.TimeUnit) @bci=49, line=389 (Compiled frame)
- - java.util.concurrent.ThreadPoolExecutor.getTask() @bci=141, line=1068 (Compiled frame)
- - java.util.concurrent.ThreadPoolExecutor.runWorker(java.util.concurrent.ThreadPoolExecutor$Worker) @bci=26, line=1130 (Compiled f
- rame)
- - java.util.concurrent.ThreadPoolExecutor$Worker.run() @bci=5, line=615 (Interpreted frame)
- - java.lang.Thread.run() @bci=11, line=744 (Interpreted frame)
- Thread 31971: (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=226 (Compiled frame)
有锁的例子-------->
代码:
- class T1 extends Thread {
- private Object lockA;
- private Object lockB;
- public T1(Object lockA,Object lockB){
- this.lockA = lockA;
- this.lockB = lockB;
- }
- @Override
- public void run() {
- System.out.println("T1 runing begin");
- synchronized (lockA) {
- try {
- Thread.sleep(1000);
- } catch (InterruptedException e) {
- }
- synchronized (lockB) {
- System.out.println("T1 runing over");
- }
- }
- }
- }
- class T2 extends Thread {
- private Object lockA;
- private Object lockB;
- public T2(Object lockA,Object lockB){
- this.lockA = lockA;
- this.lockB = lockB;
- }
- @Override
- public void run() {
- System.out.println("T2 runing begin");
- synchronized (lockB) {
- try {
- Thread.sleep(1000);
- } catch (InterruptedException e) {
- }
- synchronized (lockA) {
- System.out.println("T2 runing over");
- }
- }
- }
- }
- /**
- * @author xinchun.wang
- */
- public class LockTest {
- public static void main(String[] args) {
- Object lockA = new Object();
- Object lockB = new Object();
- T1 t1 = new T1(lockA,lockB);
- T2 t2 = new T2(lockA,lockB);
- t1.start();
- t2.start();
- }
- }
输出:
T1 runing begin
T2 runing begin
- C:\Windows\System32>jstack 22144
- 2016-08-09 20:00:10
- Full thread dump Java HotSpot(TM) 64-Bit Server VM (20.14-b01 mixed mode):
- "DestroyJavaVM" prio=6 tid=0x00000000008ac000 nid=0xd134 waiting on condition [0x0000000000000000]
- java.lang.Thread.State: RUNNABLE
- "Thread-1" prio=6 tid=0x00000000068c7000 nid=0x6d0c waiting for monitor entry [0x000000000733f000]
- java.lang.Thread.State: BLOCKED (on object monitor)
- at com.springapp.mvc.com.springapp.mvc.T2.run(LockTest.java:50)
- - waiting to lock <0x00000007d5fa25e8> (a java.lang.Object)
- - locked <0x00000007d5fa25f8> (a java.lang.Object)
- "Thread-0" prio=6 tid=0x00000000068c4800 nid=0xbf28 waiting for monitor entry [0x000000000723f000]
- java.lang.Thread.State: BLOCKED (on object monitor)
- at com.springapp.mvc.com.springapp.mvc.T1.run(LockTest.java:22)
- - waiting to lock <0x00000007d5fa25f8> (a java.lang.Object)
- - locked <0x00000007d5fa25e8> (a java.lang.Object)
- "Low Memory Detector" daemon prio=6 tid=0x00000000068b0800 nid=0xd270 runnable [0x0000000000000000]
- java.lang.Thread.State: RUNNABLE
- "C2 CompilerThread1" daemon prio=10 tid=0x00000000068a3800 nid=0xbe48 waiting on condition [0x0000000000000000]
- java.lang.Thread.State: RUNNABLE
- "C2 CompilerThread0" daemon prio=10 tid=0x0000000006859800 nid=0xd2e4 waiting on condition [0x0000000000000000]
- java.lang.Thread.State: RUNNABLE
- "Attach Listener" daemon prio=10 tid=0x0000000006858800 nid=0xb5fc waiting on condition [0x0000000000000000]
- java.lang.Thread.State: RUNNABLE
- "Signal Dispatcher" daemon prio=10 tid=0x0000000006853800 nid=0xc62c runnable [0x0000000000000000]
- java.lang.Thread.State: RUNNABLE
- "Finalizer" daemon prio=8 tid=0x0000000006845800 nid=0xcd4c in Object.wait() [0x0000000006b3f000]
- java.lang.Thread.State: WAITING (on object monitor)
- at java.lang.Object.wait(Native Method)
- - waiting on <0x00000007d5f61300> (a java.lang.ref.ReferenceQueue$Lock)
- at java.lang.ref.ReferenceQueue.remove(ReferenceQueue.java:118)
- - locked <0x00000007d5f61300> (a java.lang.ref.ReferenceQueue$Lock)
- at java.lang.ref.ReferenceQueue.remove(ReferenceQueue.java:134)
- at java.lang.ref.Finalizer$FinalizerThread.run(Finalizer.java:159)
- "Reference Handler" daemon prio=10 tid=0x0000000000828000 nid=0x92d0 in Object.wait() [0x000000000683f000]
- java.lang.Thread.State: WAITING (on object monitor)
- at java.lang.Object.wait(Native Method)
- - waiting on <0x00000007d5f611d8> (a java.lang.ref.Reference$Lock)
- at java.lang.Object.wait(Object.java:485)
- at java.lang.ref.Reference$ReferenceHandler.run(Reference.java:116)
- - locked <0x00000007d5f611d8> (a java.lang.ref.Reference$Lock)
- "VM Thread" prio=10 tid=0x0000000000822000 nid=0x7e60 runnable
- "GC task thread#0 (ParallelGC)" prio=6 tid=0x0000000000778000 nid=0xce94 runnable
- "GC task thread#1 (ParallelGC)" prio=6 tid=0x0000000000779800 nid=0xc574 runnable
- "GC task thread#2 (ParallelGC)" prio=6 tid=0x000000000077c000 nid=0x7f18 runnable
- "GC task thread#3 (ParallelGC)" prio=6 tid=0x000000000077d800 nid=0x7f1c runnable
- "VM Periodic Task Thread" prio=10 tid=0x00000000068b9800 nid=0xc3dc waiting on condition
- JNI global references: 882
- Found one Java-level deadlock:
- =============================
- "Thread-1":
- waiting to lock monitor 0x0000000006842b30 (object 0x00000007d5fa25e8, a java.lang.Object),
- which is held by "Thread-0"
- "Thread-0":
- waiting to lock monitor 0x00000000068453e0 (object 0x00000007d5fa25f8, a java.lang.Object),
- which is held by "Thread-1"
- Java stack information for the threads listed above:
- ===================================================
- "Thread-1":
- at com.springapp.mvc.com.springapp.mvc.T2.run(LockTest.java:50)
- - waiting to lock <0x00000007d5fa25e8> (a java.lang.Object)
- - locked <0x00000007d5fa25f8> (a java.lang.Object)
- "Thread-0":
- at com.springapp.mvc.com.springapp.mvc.T1.run(LockTest.java:22)
- - waiting to lock <0x00000007d5fa25f8> (a java.lang.Object)
- - locked <0x00000007d5fa25e8> (a java.lang.Object)
- Found 1 deadlock.
线程状态的分析:
Runnable:该状态表示线程具备所有运行条件,在运行队列中准备操作系统的调度,或者正在运行。
Wait on condition :
该状态出现在线程等待某个条件的发生。具体是什么原因,可以结合 stacktrace来分析。最常见的情况是线程在等待网络的读写,比如当网络数据没有准备好读时,线程处于这种等待状态,而一旦有数据准备好读之后,线程会重新激活,读取并处理数据。在 Java引入 NewIO之前,对于每个网络连接,都有一个对应的线程来处理网络的读写操作,即使没有可读写的数据,线程仍然阻塞在读写操作上,这样有可能造成资源浪费,而且给操作系统的线程调度也带来压力。在 NewIO里采用了新的机制,编写的服务器程序的性能和可扩展性都得到提高。
如果发现有大量的线程都在处在 Wait on condition,从线程 stack看, 正等待网络读写,这可能是一个网络瓶颈的征兆。因为网络阻塞导致线程无法执行。一种情况是网络非常忙,几 乎消耗了所有的带宽,仍然有大量数据等待网络读 写;另一种情况也可能是网络空闲,但由于路由等问题,导致包无法正常的到达。所以要结合系统的一些性能观察工具来综合分析,比如 netstat统计单位时间的发送包的数目,如果很明显超过了所在网络带宽的限制 ; 观察 cpu的利用率,如果系统态的 CPU时间,相对于用户态的 CPU时间比例较高;如果程序运行在 Solaris 10平台上,可以用 dtrace工具看系统调用的情况,如果观察到 read/write的系统调用的次数或者运行时间遥遥领先;这些都指向由于网络带宽所限导致的网络瓶颈。另外一种出现 Wait on condition的常见情况是该线程在 sleep,等待 sleep的时间到了时候,将被唤醒。
BLOCKED: 线程sleep 就会进入这个
锁的分析:
Found 1 deadlock.
其中:
Thread-1 持有0x00000007d5fa25f8 锁,希望获取0x00000007d5fa25e8
Thread-2 持有0x00000007d5fa25e8锁,希望获取0x00000007d5fa25f8
而
"Thread-0":
waiting to lock monitor 0x00000000068453e0 (object 0x00000007d5fa25f8, a java.lang.Object),
which is held by "Thread-1"
也会提醒:Thread-0 需要获取的0x00000007d5fa25f8 是由 Thread-1 持有。
其他:
TIME列就是各个Java线程耗费的CPU时间,CPU时间最长的是线程ID为21742的线程,用
printf "%x\n" 21742
得到21742的十六进制值为54ee,下面会用到。
OK,下一步终于轮到jstack上场了,它用来输出进程21711的堆栈信息,然后根据线程ID的十六进制值grep