jstack - Java 堆栈跟踪工具

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

使用 jstack -help 查看使用帮助:

[root@localhost ~]$ 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)    // 如果调用到本地方法的话,显示 C/C++ 的堆栈
    -l  long listing. Prints additional information about locks    // 除堆栈外,显示关于锁的附加信息
    -h or -help to print this help message   // 显示帮助信息

继续使用前面文章中的代码,我们在程序运行时打印下其线程堆栈:

[root@localhost ~]$ jstack -l 20408
2018-04-27 14:42:49
Full thread dump Java HotSpot(TM) 64-Bit Server VM (25.152-b16 mixed mode):

"Attach Listener" #10 daemon prio=9 os_prio=0 tid=0x00007f6d94001000 nid=0x4ffa waiting on condition [0x0000000000000000]
   java.lang.Thread.State: RUNNABLE

   Locked ownable synchronizers:
    - None

"Service Thread" #9 daemon prio=9 os_prio=0 tid=0x00007f6ddc0d3000 nid=0x4fca runnable [0x0000000000000000]
   java.lang.Thread.State: RUNNABLE

   Locked ownable synchronizers:
    - None

"C1 CompilerThread3" #8 daemon prio=9 os_prio=0 tid=0x00007f6ddc0c7800 nid=0x4fc9 waiting on condition [0x0000000000000000]
   java.lang.Thread.State: RUNNABLE

   Locked ownable synchronizers:
    - None

"C2 CompilerThread2" #7 daemon prio=9 os_prio=0 tid=0x00007f6ddc0c5800 nid=0x4fc8 waiting on condition [0x0000000000000000]
   java.lang.Thread.State: RUNNABLE

   Locked ownable synchronizers:
    - None

"C2 CompilerThread1" #6 daemon prio=9 os_prio=0 tid=0x00007f6ddc0c3800 nid=0x4fc7 waiting on condition [0x0000000000000000]
   java.lang.Thread.State: RUNNABLE

   Locked ownable synchronizers:
    - None

"C2 CompilerThread0" #5 daemon prio=9 os_prio=0 tid=0x00007f6ddc0c0800 nid=0x4fc6 waiting on condition [0x0000000000000000]
   java.lang.Thread.State: RUNNABLE

   Locked ownable synchronizers:
    - None

"Signal Dispatcher" #4 daemon prio=9 os_prio=0 tid=0x00007f6ddc0bf000 nid=0x4fc5 runnable [0x0000000000000000]
   java.lang.Thread.State: RUNNABLE

   Locked ownable synchronizers:
    - None

"Finalizer" #3 daemon prio=8 os_prio=0 tid=0x00007f6ddc08c000 nid=0x4fc4 in Object.wait() [0x00007f6dbfefd000]
   java.lang.Thread.State: WAITING (on object monitor)
    at java.lang.Object.wait(Native Method)
    - waiting on <0x00000000ff000a18> (a java.lang.ref.ReferenceQueue$Lock)
    at java.lang.ref.ReferenceQueue.remove(ReferenceQueue.java:143)
    - locked <0x00000000ff000a18> (a java.lang.ref.ReferenceQueue$Lock)
    at java.lang.ref.ReferenceQueue.remove(ReferenceQueue.java:164)
    at java.lang.ref.Finalizer$FinalizerThread.run(Finalizer.java:209)

   Locked ownable synchronizers:
    - None

"Reference Handler" #2 daemon prio=10 os_prio=0 tid=0x00007f6ddc087800 nid=0x4fc3 in Object.wait() [0x00007f6dbfffe000]
   java.lang.Thread.State: WAITING (on object monitor)
    at java.lang.Object.wait(Native Method)
    - waiting on <0x00000000ff000bd0> (a java.lang.ref.Reference$Lock)
    at java.lang.Object.wait(Object.java:502)
    at java.lang.ref.Reference.tryHandlePending(Reference.java:191)
    - locked <0x00000000ff000bd0> (a java.lang.ref.Reference$Lock)
    at java.lang.ref.Reference$ReferenceHandler.run(Reference.java:153)

   Locked ownable synchronizers:
    - None

"main" #1 prio=5 os_prio=0 tid=0x00007f6ddc009000 nid=0x4fb9 waiting on condition [0x00007f6de5560000]
   java.lang.Thread.State: TIMED_WAITING (sleeping)
    at java.lang.Thread.sleep(Native Method)
    at JMapOom.main(JMapOom.java:11)

   Locked ownable synchronizers:
    - None

"VM Thread" os_prio=0 tid=0x00007f6ddc07f800 nid=0x4fc2 runnable 

"GC task thread#0 (ParallelGC)" os_prio=0 tid=0x00007f6ddc01e800 nid=0x4fba runnable 

"GC task thread#1 (ParallelGC)" os_prio=0 tid=0x00007f6ddc020000 nid=0x4fbb runnable 

"GC task thread#2 (ParallelGC)" os_prio=0 tid=0x00007f6ddc022000 nid=0x4fbc runnable 

"GC task thread#3 (ParallelGC)" os_prio=0 tid=0x00007f6ddc024000 nid=0x4fbd runnable 

"GC task thread#4 (ParallelGC)" os_prio=0 tid=0x00007f6ddc025800 nid=0x4fbe runnable 

"GC task thread#5 (ParallelGC)" os_prio=0 tid=0x00007f6ddc027800 nid=0x4fbf runnable 

"GC task thread#6 (ParallelGC)" os_prio=0 tid=0x00007f6ddc029000 nid=0x4fc0 runnable 

"GC task thread#7 (ParallelGC)" os_prio=0 tid=0x00007f6ddc02b000 nid=0x4fc1 runnable 

"VM Periodic Task Thread" os_prio=0 tid=0x00007f6ddc0d8000 nid=0x4fcb waiting on condition 

JNI global references: 6

文章摘自《深入理解Java虚拟机》第二版 周志明著,仅作为学习记录,书籍中用到的案例代码及描述有部分修改,但未改变原意。