美文网首页
使用jstack分析Java线程

使用jstack分析Java线程

作者: 我不懂我不懂a | 来源:发表于2024-02-28 16:53 被阅读0次

You use the jstack command to print Java stack traces of Java threads for a specified Java process. This command is experimental and unsupported.

官方文档中,jstack是用于打印指定Java进程的线程堆栈跟踪,我们通常用jstack来分析死锁和死循环等场景。

使用方式及参数

Usage:
    jstack [-l][-e] <pid>
        (to connect to running process)

Options:
    -l  long listing. Prints additional information about locks
    -e  extended listing. Prints additional information about threads
    -? -h --help -help to print this help message

使用方式是找到Java进程id——pid,jstack pid就能打印出堆栈信息。-l参数可以打印锁的信息,-e可以打印线程的额外信息。

jstack分析死锁

我们写一个死锁的demo DeadlockDemo.java并且运行:

Object lock1 = new Object();  
Object lock2 = new Object();  
  
Thread t1 = new Thread(() -> {  
    synchronized (lock1) {  
        System.out.println("Thread 1 acquired lock1");  
        try {  
            sleep(1000);  
        } catch (InterruptedException e) {  
            e.printStackTrace();  
        }  
        synchronized (lock2) {  
            System.out.println("Thread 1 acquired lock2");  
        }  
    }  
});  
  
Thread t2 = new Thread(() -> {  
    synchronized (lock2) {  
        System.out.println("Thread 2 acquired lock2");  
        try {  
            sleep(1000);  
        } catch (InterruptedException e) {  
            e.printStackTrace();  
        }  
        synchronized (lock1) {  
            System.out.println("Thread 2 acquired lock1");  
        }  
    }  
});  
  
t1.start();  
t2.start();  
  
// 等待两个线程执行完毕  
try {  
    t1.join();  
    t2.join();  
} catch (InterruptedException e) {  
    e.printStackTrace();  
}  
  
System.out.println("Main thread finished");

使用jps -l查看java程序的端口

jps -l
12406 org.jetbrains.jps.cmdline.Launcher
2156 com.intellij.idea.Main
17119 jdk.jcmd/sun.tools.jps.Jps

命令行执行jstack -l -e 12406

2024-02-15 15:30:11
Full thread dump OpenJDK 64-Bit Server VM (17.0.9+9-Ubuntu-120.04 mixed mode, sharing):

第一部分是虚拟机信息,SMR全称是Safe Memory Reclamation,即jvm安全分配的线程:

Threads class SMR info:
_java_thread_list=0x00007f102c001740, length=14, elements={
0x00007f10c0013af0, 0x00007f10c01765a0, 0x00007f10c0177990, 0x00007f10c017e170,
0x00007f10c017f530, 0x00007f10c0180950, 0x00007f10c0182310, 0x00007f10c0183850,
0x00007f10c018ccc0, 0x00007f10c01985d0, 0x00007f10c01c53c0, 0x00007f10c04d9610,
0x00007f10c04e48d0, 0x00007f102c000d20
}

第二部分是线程堆栈信息,堆栈信息里第一行是线程的元信息:

"main" #1 prio=5 os_prio=0 cpu=338.57ms elapsed=91.48s allocated=14953K defined_classes=1526 tid=0x00007f10c0013af0 nid=0x2a95 in Object.wait()  [0x00007f10c7d34000]
  • "main"线程名字
  • #1线程序号
  • prio优先级
  • os_prioos线程优先级
  • cpu线程获得cpu的时间
  • elapsed线程启动后经过的wall clock time
  • allocated分配的内存字节数
  • defined_classes线程定义的类个数
  • tid线程id
  • nidos线程id
  • in Object.wait()表示当前线程状态
  • [0x00007f10c7d34000]最新java堆栈指针sp
   java.lang.Thread.State: WAITING (on object monitor)
    at java.lang.Object.wait(java.base@17.0.9/Native Method)
    - waiting on <0x000000071e77a5b0> (a java.lang.Thread)
    at java.lang.Thread.join(java.base@17.0.9/Thread.java:1313)
    - locked <0x000000071e77a5b0> (a java.lang.Thread)
    at java.lang.Thread.join(java.base@17.0.9/Thread.java:1381)
    at org.example.DeadlockDemo.main(DeadlockDemo.java:43)
    at jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(java.base@17.0.9/Native Method)
    at jdk.internal.reflect.NativeMethodAccessorImpl.invoke(java.base@17.0.9/NativeMethodAccessorImpl.java:77)
    at jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(java.base@17.0.9/DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(java.base@17.0.9/Method.java:568)
    at com.sun.tools.javac.launcher.Main.execute(jdk.compiler@17.0.9/Main.java:419)
    at com.sun.tools.javac.launcher.Main.run(jdk.compiler@17.0.9/Main.java:192)
    at com.sun.tools.javac.launcher.Main.main(jdk.compiler@17.0.9/Main.java:132)

后面跟着的是堆栈的详细信息,表示当前main线程状态是WAITING,表示正在执行Thread.join中,还在等待其他线程执行完。Locked ownable synchronizers:代表线程拥有的排它锁对象,例如ReentrantReadWriteLock.writeLock


"VM Thread" os_prio=0 cpu=15.08ms elapsed=91.47s tid=0x00007f10c01724e0 nid=0x2a9b runnable  

"GC Thread#0" os_prio=0 cpu=0.14ms elapsed=91.48s tid=0x00007f10c007be30 nid=0x2a96 runnable  

"G1 Main Marker" os_prio=0 cpu=0.13ms elapsed=91.48s tid=0x00007f10c008c3e0 nid=0x2a97 runnable  

"G1 Conc#0" os_prio=0 cpu=0.08ms elapsed=91.48s tid=0x00007f10c008d350 nid=0x2a98 runnable  

"G1 Refine#0" os_prio=0 cpu=0.14ms elapsed=91.48s tid=0x00007f10c0144bc0 nid=0x2a99 runnable  

"G1 Service" os_prio=0 cpu=16.20ms elapsed=91.48s tid=0x00007f10c0145ac0 nid=0x2a9a runnable  

"VM Periodic Task Thread" os_prio=0 cpu=59.59ms elapsed=91.45s tid=0x00007f10c01c6d80 nid=0x2aa6 waiting on condition  

JNI global refs: 9, weak refs: 0

后面跟着的是jvm的线程信息。

Found one Java-level deadlock:
=============================
"Thread-0":
  waiting to lock monitor 0x00007f1008001120 (object 0x000000071e77a520, a java.lang.Object),
  which is held by "Thread-1"

"Thread-1":
  waiting to lock monitor 0x00007f0ffc000f60 (object 0x000000071e77a510, a java.lang.Object),
  which is held by "Thread-0"

Java stack information for the threads listed above:
===================================================
"Thread-0":
    at org.example.DeadlockDemo.lambda$main$0(DeadlockDemo.java:19)
    - waiting to lock <0x000000071e77a520> (a java.lang.Object)
    - locked <0x000000071e77a510> (a java.lang.Object)
    at org.example.DeadlockDemo$$Lambda$198/0x00007f1044140208.run(Unknown Source)
    at java.lang.Thread.run(java.base@17.0.9/Thread.java:840)
"Thread-1":
    at org.example.DeadlockDemo.lambda$main$1(DeadlockDemo.java:33)
    - waiting to lock <0x000000071e77a510> (a java.lang.Object)
    - locked <0x000000071e77a520> (a java.lang.Object)
    at org.example.DeadlockDemo$$Lambda$199/0x00007f1044140430.run(Unknown Source)
    at java.lang.Thread.run(java.base@17.0.9/Thread.java:840)

Found 1 deadlock.

在堆栈信息的最后,jstack已经帮我们找到了死锁的原因,可以看到,thread-0锁住了<0x000000071e77a510>对象,正在等待<0x000000071e77a520>对象的释放,thread-1则相反。

jstack分析死循环

通过top找到占用大的java进程然后通过top -Hp pid找到占用异常的线程id21484,通过printf "%x\n"转换位16进制的pid,再去jstack输出找到对应堆栈执行位置进行分析jstack <pid> | grep -A 20 '<nid>'

引用资料:
[1] JDK14性能管理工具:jstack使用介绍
[2] 原来jdk自带了这么好玩的工具 —— 使用 jstack定位死循环

相关文章

  • JDK的bin下的工具有哪些功能

    Java生产环境下问题排查 Java内存泄漏分析系列之一:使用jstack定位线程堆栈信息 Java内存泄漏分析系...

  • jstack使用

    使用jstack分析指定应用线程使用异常排除。 使用jstack命令dump线程信息,例如查看Pid为3117的进...

  • 查看java线程占用cpu情况

    使用jps找出java进程的pid top -Hp VMID jstack -l VMID 分析线程栈运行情况

  • jvm 性能调优工具之 jstack

    概述 jstack是jdk自带的线程堆栈分析工具,使用该命令可以查看或导出 Java 应用程序中线程堆栈信息。 J...

  • jvm 性能调优工具之 jstack

    概述 jstack是jdk自带的线程堆栈分析工具,使用该命令可以查看或导出 Java 应用程序中线程堆栈信息。 J...

  • JVM 线程分析

    使用 导出线程堆栈:jstack pid > c:/file.txt 线程状态 Java官方定义的线程状态有6种,...

  • jstack(Java Stack Trace)简介

    jstack(Java Stack Trace)简介 jstack:Java进程中线程的堆栈信息跟踪工具。功能简介...

  • 【java】java 线程在线分析工具

    jstack(查看线程)、jmap(查看内存)和jstat(性能分析) jstack - Stack Trace ...

  • jstack分析java线程详情

    打开cmd 输入jps命令,jps很简单可以直接显示java进程的pid 输入jstack 即可查看该进程下线程...

  • 性能问题定位

    linux java jstack看java线程细节 top看线程java列表 mysql 查看当前连接数 (my...

网友评论

      本文标题:使用jstack分析Java线程

      本文链接:https://www.haomeiwen.com/subject/aslfzdtx.html