天天看點

JVM 性能調優工具 jstackJstack 用法Jstack 使用死鎖示例

Jstack 用法

$ 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)
    -l  long listing. Prints additional information about locks
    -h or -help to print this help message           

參數說明:

  • -l 長清單. 列印關于鎖的附加資訊,例如屬于java.util.concurrent 的 ownable synchronizers清單
  • -F 當’jstack [-l] pid’沒有相應的時候強制列印棧資訊
  • -m 列印java和native c/c++架構的所有棧資訊
  • -h | -help 列印幫助資訊
  • pid 需要被列印配置資訊的java程序id,可以用jps查詢

Jstack 使用

通過使用 jps 指令擷取需要監控的程序的pid,然後使用 jstack pid 指令檢視線程的堆棧資訊。

$ jstack 4628
2019-05-08 13:52:47
Full thread dump Java HotSpot(TM) 64-Bit Server VM (25.161-b12 mixed mode):

"NettythreadDeathWatcher-2-1" #17 daemon prio=1 os_prio=-2 tid=0x0000000018473800 nid=0x5aa4 waiting on condition [0x000000001b9af000]
   java.lang.Thread.State: TIMED_WAITING (sleeping)
        at java.lang.Thread.sleep(Native Method)
        at io.netty.util.ThreadDeathWatcher$Watcher.run(ThreadDeathWatcher.java:152)
        at io.netty.util.concurrent.DefaultThreadFactory$DefaultRunnableDecorator.run(DefaultThreadFactory.java:138)
        at java.lang.Thread.run(Thread.java:748)

"DestroyJavaVM" #15 prio=5 os_prio=0 tid=0x0000000018476800 nid=0x2a28 waiting on condition [0x0000000000000000]
   java.lang.Thread.State: RUNNABLE

"JPS event loop" #10 prio=5 os_prio=0 tid=0x00000000175d1000 nid=0x4cac runnable [0x0000000017b8f000]
   java.lang.Thread.State: RUNNABLE
        at sun.nio.ch.WindowsSelectorImpl$SubSelector.poll0(Native Method)
        at sun.nio.ch.WindowsSelectorImpl$SubSelector.poll(WindowsSelectorImpl.java:296)
        at sun.nio.ch.WindowsSelectorImpl$SubSelector.access$400(WindowsSelectorImpl.java:278)
        at sun.nio.ch.WindowsSelectorImpl.doSelect(WindowsSelectorImpl.java:159)
        at sun.nio.ch.SelectorImpl.lockAndDoSelect(SelectorImpl.java:86)
        - locked <0x00000000d541b7c0> (a io.netty.channel.nio.SelectedSelectionKeySet)
        - locked <0x00000000d541b7b0> (a java.util.Collections$UnmodifiableSet)
        - locked <0x00000000d541b730> (a sun.nio.ch.WindowsSelectorImpl)
        at sun.nio.ch.SelectorImpl.select(SelectorImpl.java:97)
        at io.netty.channel.nio.SelectedSelectionKeySetSelector.select(SelectedSelectionKeySetSelector.java:62)
        at io.netty.channel.nio.NioEventLoop.select(NioEventLoop.java:752)
        at io.netty.channel.nio.NioEventLoop.run(NioEventLoop.java:408)
        at io.netty.util.concurrent.SingleThreadEventExecutor$5.run(SingleThreadEventExecutor.java:858)
        at java.lang.Thread.run(Thread.java:748)           

通過 jstack 指令可以擷取目前程序的所有線程資訊。

每個線程堆中資訊中,都可以檢視到 線程ID、線程的狀态(wait、sleep、running 等狀态)、是否持有鎖資訊等。

死鎖示例

下面通過一個例子,來示範 jstack 檢查死鎖的一個例子,代碼如下:

public static void deathLock() {
    Thread t1 = new Thread() {
        @Override
        public void run() {
            try {
                lock1.lock();
                TimeUnit.SECONDS.sleep(1);
                lock2.lock();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    };
    Thread t2 = new Thread() {
        @Override
        public void run() {
            try {
                lock2.lock();
                TimeUnit.SECONDS.sleep(1);
                lock1.lock();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    };
    t1.setName("mythread1");
    t2.setName("mythread2");
    t1.start();
    t2.start();
}           

使用 jstack -l pid 檢視線程堆棧資訊,發現在堆棧資訊最後面檢查出了一個死鎖。如下圖

JVM 性能調優工具 jstackJstack 用法Jstack 使用死鎖示例

可以清楚的看出 mythread2 等待 這個鎖 “0x00000000d6eb82d0”,這個鎖是由于mythread1線程持有。

mythread1線程等待這個鎖“0x00000000d6eb8300”,這個鎖是由mythread2線程持有。

“mythread1”線程堆棧資訊如下:

JVM 性能調優工具 jstackJstack 用法Jstack 使用死鎖示例
可以看出目前線程持有“0x00000000d6eb82d0”鎖,等待“0x00000000d6eb8300”的鎖

“mythread2”線程堆棧資訊如下:

JVM 性能調優工具 jstackJstack 用法Jstack 使用死鎖示例
“mythread2”的堆棧資訊中可以看出目前線程持有“0x00000000d6eb8300”鎖,等待“0x00000000d6eb82d0”的鎖。