java命令--jstack的使用

jstack用于生成java虚拟机当前时刻的线程快照。可以用来分析线程问题(如死锁),CPU突然飙升问题

1. 案例一 找出死锁

1.1 问题代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
public class DeadLockTest {

private static Object lock1 = new Object();
private static Object lock2 = new Object();

public static void main(String[] args) {
new Thread(() -> {
synchronized (lock1) {
try {
System.out.println("thread1 begin");
Thread.sleep(5000);
} catch (InterruptedException e) {
}
synchronized (lock2) {
System.out.println("thread1 end");
}
}
}).start();

new Thread(() -> {
synchronized (lock2) {
try {
System.out.println("thread2 begin");
Thread.sleep(5000);
} catch (InterruptedException e) {
}
synchronized (lock1) {
System.out.println("thread2 end");
}
}
}).start();

System.out.println("main thread end");
}
}

1.2 问题定位

1.2.1 方式一 jps+jstack

  1. 运行jps,查看当前所有java进程的pid
  2. jstack pid 查看当前进程的堆栈状态,如果有死锁会打印出来found 1 deadLock

image-20230228231139474

​ 可以定位出是17行出了死锁问题。

1.2.2 方式二 jvisualvm自动检测死锁

代码运行起来后,启动jvisualvm,在线程页面会直接有一个红色的显示:监测到死锁

image-20230228231151238

2 案例二 找出占用cpu最高的线程堆栈信息

2.1 问题代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
public class Math {

public static final int initData = 666;
public static User user = new User();

public int compute() { //一个方法对应一块栈帧内存区域
int a = 1;
int b = 2;
int c = (a + b) * 10;
return c;
}

public static void main(String[] args) {
Math math = new Math();
while (true) {
math.compute();
}
}
}

2.2 问题定位

2.2.1 命令top -p ,显示你的java进程的内存情况,找到当前进程的PID

image-20230228231203454

2.2.2 按H,获取每个线程的内存情况

2.2.3 找到内存和cpu占用最高的线程tid

2.2.4 执行 jstack PID|grep -A 10 4cd0

比如tid为19664 ,转为十六进制得到 0x4cd0,执行 jstack 19663|grep -A 10 4cd0,得到线程堆栈信息中 4cd0 这个线程所在行的后面10行,从堆栈中可以发现导致cpu飙高的调用方法

image-20230228231212070

6,查看对应的堆栈信息找出可能存在问题的代码


java命令--jstack的使用
http://example.com/java命令-jstack-工具/
作者
Panyurou
发布于
2022年6月25日
许可协议