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 &
核心步骤
jps
打印 Java 进程(查看是否启动)
zhengsh@zhengsh:/opt/apps$ jps 4541 MathTest 4559 Jps
top
命令,查询指定进程的线程信息,然后通过 shift + p 通过 cpu 占用排序
top -Hp 4541
结果如下:
找到高占用 cpu 的线程 id 4542
- 通过 pid 转化为 16 进制
printf "%x\n" 4542 11be
- 查询所在的后面 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 过高。问题找到,解决完毕。
参考资料
- 《深入理解 JVM 虚拟机 第四版》周志明