JVM 性能调优工具 jstack

简介: Jstack是jdk自带的线程堆栈分析工具,使用该命令可以查看或导出 Java 应用程序中线程堆栈信息。

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 查看线程堆栈信息,发现在堆栈信息最后面检查出了一个死锁。如下图

image

可以清楚的看出 mythread2 等待 这个锁 “0x00000000d6eb82d0”,这个锁是由于mythread1线程持有。
mythread1线程等待这个锁“0x00000000d6eb8300”,这个锁是由mythread2线程持有。

“mythread1”线程堆栈信息如下:

image

可以看出当前线程持有“0x00000000d6eb82d0”锁,等待“0x00000000d6eb8300”的锁

“mythread2”线程堆栈信息如下:

image

“mythread2”的堆栈信息中可以看出当前线程持有“0x00000000d6eb8300”锁,等待“0x00000000d6eb82d0”的锁。

相关文章
|
3月前
|
缓存 Java 中间件
jvm性能调优实战 -55RPC调用引发的OOM故障
jvm性能调优实战 -55RPC调用引发的OOM故障
57 0
|
3月前
|
缓存 监控 Java
jvm性能调优实战 - 48无限循环调用和没有缓存的动态代理引起的OOM
jvm性能调优实战 - 48无限循环调用和没有缓存的动态代理引起的OOM
39 0
|
3月前
|
消息中间件 存储 Java
jvm性能调优实战 - 47超大数据量处理系统是如何OOM的
jvm性能调优实战 - 47超大数据量处理系统是如何OOM的
42 0
|
3月前
|
Java
jvm性能调优实战 - 46堆区OOM解析
jvm性能调优实战 - 46堆区OOM解析
39 0
|
3月前
|
缓存 监控 算法
jvm性能调优实战 - 39一次大促导致的内存泄漏和Full GC优化
jvm性能调优实战 - 39一次大促导致的内存泄漏和Full GC优化
68 0
|
3月前
|
架构师 Java
jvm性能调优实战 - 35电商APP后台系统如何对Full GC进行深度优化
jvm性能调优实战 - 35电商APP后台系统如何对Full GC进行深度优化
52 0
|
2月前
|
监控 算法 NoSQL
深入理解JVM - 实战JVM工具(上)
深入理解JVM - 实战JVM工具(上)
69 0
|
3月前
|
监控 Java 应用服务中间件
jvm性能调优实战 -58类加载器过多引发的OOM问题
jvm性能调优实战 -58类加载器过多引发的OOM问题
43 0
|
3月前
|
Java 应用服务中间件
jvm性能调优实战 - 45无限制的调用方法导致栈溢出OOM
jvm性能调优实战 - 45无限制的调用方法导致栈溢出OOM
43 0
|
3月前
|
安全 IDE Java
jvm性能调优实战 - 44Metaspace区域是如何因为类太多而发生内存溢出OOM
jvm性能调优实战 - 44Metaspace区域是如何因为类太多而发生内存溢出OOM
128 0