0%

jstack 基本命令

JDK 的 bin 目录下为 Java 开发人员提供了很多实用的小工具,很多场景下都会用到它们,比如:打包、部署、签名、调试、监控、运维等。本文介绍其中一款:

jstack (Stack Trace for Java): Java 堆栈跟踪工具

功能

生成虚拟机当前时刻的线程快照(一般称为 threaddump 或者 javacore 文件)。

线程快照就是当前虚拟机内每一条线程正在执行的方法堆栈的集合,生成线程快照的目的通常是定位线程出现长时间停顿的原因,如线程间死锁、死循环、请求外部资源导致的长时间挂起等,都是导致线程长时间停顿的常见原因。

线程出现停顿时通过 jstack 来查看各个线程的调用堆栈,就可以获知没有响应的线程到底在后台做些什么事情,或者等待着什么资源。

命令格式

1
jstack [ option ] vmid

option

选项 作用
-F 当正常输出的请求不被响应时,强制输出线程堆栈
-l 除堆栈外,显示关于锁的附加信息
-m 如果调用到本地方法的话,可以显示 C/C++ 的堆栈

执行样例

使用 jstack 查看线程堆栈

1
$ jstack 5511

统计线程数

1
$ jstack 5511 | grep 'java.lang.Thread.State' | wc -l

使用 jstack 定位进程中 cpu 占用最高的线程

  1. 查看 cpu 占用高线程
  • -H: 指示 top 命令显示单个线程。如果没有该选项,则显示每个进程中的线程总和

  • -p: 后跟进程 ID (process id),这里为 LVMID

1
$ top -H -p 5511

  1. 转换线程 ID
1
$ printf "%x\n" 6072

  1. 定位进程中 cpu 占用最高的线程
  • -A: 往下展示 x 行信息

  • -B: 往上展示 x 行信息

加上 -A 或 -B,可以打印出线程具体的堆栈信息

1
$ jstack 5511 | grep 17b8 -A 10

同理检测 cpu 高的原因

  • 使用 top 命令找到 cpu 占用最高的进程

  • 查看进程中 cpu 占用最高的线程(同上)寻找原因

reference: top

使用 jstack 检测死锁

  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
36
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

public class DeathLockDemo {

private static final Lock LOCK_1 = new ReentrantLock(), LOCK_2 = new ReentrantLock();

public static void deathLock() {
Thread t1 = new Thread(() -> {
try {
LOCK_1.lock();
TimeUnit.SECONDS.sleep(1);
LOCK_2.lock();
} catch (InterruptedException e) {
e.printStackTrace();
}
}, "death_lock_demo_thread1");
Thread t2 = new Thread(() -> {
try {
LOCK_2.lock();
TimeUnit.SECONDS.sleep(1);
LOCK_1.lock();
} catch (InterruptedException e) {
e.printStackTrace();
}
}, "death_lock_demo_thread2");

t1.start();
t2.start();
}

public static void main(String[] args) {
deathLock();
}
}
  1. demo 运行后 jps 查询 LVMID 为 33391:
1
$ jps -l | grep DeathLockDemo
  1. 使用 jstack 检测死锁
1
$ jstack -l 33391

关键信息如下:



欢迎关注我的其它发布渠道