使用jstack分析Java线程

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] 
        (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([email protected]/Native Method)
    - waiting on <0x000000071e77a5b0> (a java.lang.Thread)
    at java.lang.Thread.join([email protected]/Thread.java:1313)
    - locked <0x000000071e77a5b0> (a java.lang.Thread)
    at java.lang.Thread.join([email protected]/Thread.java:1381)
    at org.example.DeadlockDemo.main(DeadlockDemo.java:43)
    at jdk.internal.reflect.NativeMethodAccessorImpl.invoke0([email protected]/Native Method)
    at jdk.internal.reflect.NativeMethodAccessorImpl.invoke([email protected]/NativeMethodAccessorImpl.java:77)
    at jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke([email protected]/DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke([email protected]/Method.java:568)
    at com.sun.tools.javac.launcher.Main.execute([email protected]/Main.java:419)
    at com.sun.tools.javac.launcher.Main.run([email protected]/Main.java:192)
    at com.sun.tools.javac.launcher.Main.main([email protected]/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([email protected]/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([email protected]/Thread.java:840)

Found 1 deadlock.

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

jstack分析死循环

使用jstack分析Java线程_第1张图片
使用jstack分析Java线程_第2张图片
通过top找到占用大的java进程然后通过top -Hp pid找到占用异常的线程id21484,通过转换位16进制的pid,再去jstack输出找到对应堆栈执行位置进行分析。

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

你可能感兴趣的:(java)