jstack 为给定的 Java 进程或核心文件或远程调试服务器打印 Java 线程的 Java 堆栈跟踪。对于每个 Java 框架,将打印完整的类名、方法名、‘bci’(字节码索引)和行号(如果有)。使用 -m 选项,jstack 会打印所有线程的 Java 和本机帧以及“pc”(程序计数器)。对于每个原生帧,如果可用,将打印最接近“pc”的原生符号。C++ 重整名称不会被重整。要对 C++ 名称进行解码,此命令的输出可以通过管道传送到c++filt。如果给定进程在 64 位 VM 上运行,您可能需要指定-J-d64选项,
jstack
- jstack用于生成java虚拟机当前时刻的线程快照。
- 线程快照是当前java虚拟机内每一条线程正在执行的方法堆栈的集合,生成线程快照的主要目的是定位线程出现长时间停顿的原因,如线程间死锁、死循环、请求外部资源导致的长时间等待等。
- 线程出现停顿的时候通过jstack来查看各个线程的调用堆栈,就可以知道没有响应的线程到底在后台做什么事情,或者等待什么资源。
- 如果java程序崩溃生成core文件,jstack工具可以用来获得core文件的java stack和native stack的信息,从而可以轻松地知道java程序是如何崩溃和在程序何处发生问题。
- 另外,jstack工具还可以附属到正在运行的java程序中,看到当时运行的java程序的java stack和native stack的信息, 如果现在运行的java程序呈现hung的状态,jstack是非常有用的。
jstack输出的线程栈信息中,线程ID是以十六进制展示的
1
2
3
4
5
6
7
8
|
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死锁
步骤
- 在终端中输入
jsp
查看当前运行的java程序
- 使用
jstack -l pid
查看线程堆栈信息
- 分析堆栈信息
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
36
37
38
39
40
41
42
43
44
45
46
|
/**
* Java 死锁demo
*/
public class DeathLockTest {
private static Lock lock1 = new ReentrantLock();
private static Lock lock2 = new ReentrantLock();
public static void deathLock() {
Thread t1 = new Thread() {
@Override
public void run() {
try {
lock1.lock();
System.out.println(Thread.currentThread().getName() + " get the lock1");
Thread.sleep(1000);
lock2.lock();
System.out.println(Thread.currentThread().getName() + " get the lock2");
} catch (InterruptedException e) {
e.printStackTrace();
}
}
};
Thread t2 = new Thread() {
@Override
public void run() {
try {
lock2.lock();
System.out.println(Thread.currentThread().getName() + " get the lock2");
Thread.sleep(1000);
lock1.lock();
System.out.println(Thread.currentThread().getName() + " get the lock1");
} catch (InterruptedException e) {
e.printStackTrace();
}
}
};
//设置线程名字,方便分析堆栈信息
t1.setName("mythread-jay");
t2.setName("mythread-tianluo");
t1.start();
t2.start();
}
public static void main(String[] args) {
deathLock();
}
}
|
分析CPU过高(100%)问题
1
2
3
4
5
6
7
8
9
|
# P(shift+p) cpu排序 找到cpu占用高的 pid
top
# -H 可以查看由某个进程启动的所有线程 P cpu排序找到最大线程 pid 这里为 tid
top -Hp <pid>
# 将 tid 转 16进制 因为 jstack 输出的进程栈信息中,线程ID是以十六进制展示
printf "%x\n" <tid>
# jstack pid | grep '<16进制 tid>'
# -A 100 输出 100 行
jstack <pid> | grep '<16进制 tid>' -A 100 > ~/Downloads/cpu-100.txt
|
- 使用
top -Hp <pid>
命令找出进程中占用cpu最高的前几个线程
- 使用jstack获取线程快照,然后使用线程id搜索分析快照文件
- 如果线程调用了业务相关代码,则分析是否是代码问题导致的cpu占用过高,如果线程是VM Thread,则应该监控检查垃圾回收活动频率,看是否是因为频繁进行垃圾回收导致的。
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
|
**
* 有个导致CPU过高程序的demo,死循环
*/
public class JstackCase {
private static ExecutorService executorService = Executors.newFixedThreadPool(5);
public static void main(String[] args) {
Task task1 = new Task();
Task task2 = new Task();
executorService.execute(task1);
executorService.execute(task2);
}
public static Object lock = new Object();
static class Task implements Runnable{
public void run() {
synchronized (lock){
long sum = 0L;
while (true){
sum += 1;
}
}
}
}
}
|