jstack 工具
jstack(Stack Trace for Java) 命令用于生成当前时刻的线程快照(一般称为 threaddump 文件)。
线程快照就是当前虚拟机每条线程正在执行的方法堆栈集合,生成线程快照的目的通常是定位线程出现长时间停顿的原因,如线程间死锁,死循环、请求外部资源导致的长时间挂起等,都是导致线程长时间停顿的原因。
线程出现停顿是通过 jstack 来查看各个线层呢的调用堆栈,就可以获知没有响应的线程到底在后台做什么,或者等待什么资源。
jstack 命令格式:
jstack [option] vmid
下面我们就开始实践,说下环境:jdk 1.8, 操作系统 ubantu 20.04。
排查 CPU 高占用问题
我们先写一个简单的死循环程序,来模拟 CPU 高占用问题。
测试代码如下:
public class MathTest {
public int compute() {
int a = 1026;
int b = 2018;
return (a + b) * 10;
}
public static void main(String[] args) {
MathTest math = new MathTest();
//System.out.println(math.compute());
while (true) {
math.compute();
}
}
}
编译和执行命令如下:
// 编译
javac MathTest.java
// 后台执行
java MathTest &
核心步骤
1. jps 打印 Java 进程(查看是否启动)
zhengsh@zhengsh:/opt/apps$ jps
4541 MathTest
4559 Jps
2. top 命令,查询指定进程的线程信息,然后通过 shift + p 排序
top -Hp 4541
结果如下:
找到高占用 cpu 的线程 id 4542
3. 通过 pid 转化为 16 进制
printf "%x\n" 4542
11be
4. 查询所在的后面 30 行
jstack 4541|grep 11be -A 30
// 显示结果如下:
"main" #1 prio=5 os_prio=0 tid=0x00007f8efc00a800 nid=0x11be runnable [0x00007f8f016a3000]
java.lang.Thread.State: RUNNABLE
at MathTest.main(MathTest.java:13)
"VM Thread" os_prio=0 tid=0x00007f8efc074000 nid=0x11c1 runnable
"GC task thread#0 (ParallelGC)" os_prio=0 tid=0x00007f8efc01f800 nid=0x11bf runnable
"GC task thread#1 (ParallelGC)" os_prio=0 tid=0x00007f8efc021000 nid=0x11c0 runnable
"VM Periodic Task Thread" os_prio=0 tid=0x00007f8efc0d9000 nid=0x11c8 waiting on condition
JNI global references: 5
我们可以查询到 MathTest 类 13 行正在运行,在回看代码:
这里是有死循环调用,导致 CPU 过高。问题找到,解决完毕。