昨天博客项目突然宕机,CPU占用接近100%,连敲命令都卡。
tomcat日志也把磁盘占满了,十分异常。
后来排查发现原来是RabbitMQ的一个消息始终无法被消费,一直存在队列中,
导致每秒执行一次消费代码,最终日志把磁盘占满,服务器宕机…
排查问题时,用到了Java自带的工具----jstack。
觉得非常有用,特记录。
##jstack是啥?
引用百度百科的解释如下:
jstack是java虚拟机自带的一种堆栈跟踪工具。
jstack用于生成java虚拟机当前时刻的线程快照。线程快照是当前java虚拟机内每一条线程正在执行的方法堆栈的集合,生成线程快照的主要目的是定位线程出现长时间停顿的原因,如线程间死锁、死循环、请求外部资源导致的长时间等待等。
线程出现停顿的时候通过jstack来查看各个线程的调用堆栈,就可以知道没有响应的线程到底在后台做什么事情,或者等待什么资源。
jstack是jdk自带的线程堆栈分析工具,使用该命令可以查看或导出 Java 应用程序中线程堆栈信息。
命令格式
jstack [ option ] pid
基本参数:
- -F 当’jstack [-l] pid’没有响应的时候强制打印栈信息
- -l 长列表. 打印关于锁的附加信息,例如属于java.util.concurrent的ownable synchronizers列表.
- -m 打印java和native c/c++框架的所有栈信息. -h | -help打印帮助信息
- pid 需要被打印配置信息的java进程id,可以用jps工具查询.
实际应用
1、首先编写一个死循环程序
为了测试,编写一个死循环程序,打成jar包放到服务器上运行。
代码如下:
public static void main(String[] args) {
while (true) {
Object o = new Object();
}
}
2、使用top -Hp 查看异常线程
没有运行时,CPU占用几乎为0:
Cpu(s): 0.0%us, 0.0%sy, 0.0%ni, 99.9%id, 0.0%wa, 0.0%hi, 0.0%si, 0.0%st
运行死循环代码,CPU占用迅速飙升:
PID USER PR NI VIRT RES SHR S %CPU %MEM TIME+ COMMAND
3080 root 20 0 5242m 29m 11m S 100.1 0.3 0:15.64 java
可以看到进程ID为3080占用CPU100%
得到进程ID后,我们需要获取到具体的线程ID,然后用jstack分析。
命令:top -Hp 【进程ID】
top -Hp 3080
结果如下,线程ID为3081:
PID USER PR NI VIRT RES SHR S %CPU %MEM TIME+ COMMAND
3081 root 20 0 5242m 48m 11m R 99.9 0.5 1:09.71 java
需要将线程ID转换为十六进制,直接在Linux中即可转换。
命令:printf ‘%x\n’ 【十进制数】 (\n只为换行显示,单纯的转换只需要%x 即可)
printf ‘%x\n’ 3081
得到3081的十六进制是 c09。
3、使用jstack分析
命令:jstack 【进程ID】 | grep 0x【线程ID十六进制】 -A 30(显示后30行)
jstack 3080 | grep 0xc09 -A 30
"main" #1 prio=5 os_prio=0 tid=0x00007f134c04b000 nid=0xc09 runnable [0x00007f1352fcd000]
java.lang.Thread.State: RUNNABLE
at item01.Demo.main(Demo.java:13)
"VM Thread" os_prio=0 tid=0x00007f134c224000 nid=0xc12 runnable
"GC task thread#0 (ParallelGC)" os_prio=0 tid=0x00007f134c05d800 nid=0xc0a runnable
"GC task thread#1 (ParallelGC)" os_prio=0 tid=0x00007f134c05f800 nid=0xc0b runnable
"GC task thread#2 (ParallelGC)" os_prio=0 tid=0x00007f134c061000 nid=0xc0c runnable
"GC task thread#3 (ParallelGC)" os_prio=0 tid=0x00007f134c063000 nid=0xc0d runnable
"GC task thread#4 (ParallelGC)" os_prio=0 tid=0x00007f134c064800 nid=0xc0e runnable
"GC task thread#5 (ParallelGC)" os_prio=0 tid=0x00007f134c066800 nid=0xc0f runnable
"GC task thread#6 (ParallelGC)" os_prio=0 tid=0x00007f134c068800 nid=0xc10 runnable
"GC task thread#7 (ParallelGC)" os_prio=0 tid=0x00007f134c06a000 nid=0xc11 runnable
"VM Periodic Task Thread" os_prio=0 tid=0x00007f134c27f000 nid=0xc1b waiting on condition
JNI global references: 5
从结果中我们已经可以看到,Demo.java的13行代码有问题。
GC一直在不停的跑,不停的回收对象,导致CPU占用过高。
jstack是JDK自带的堆栈分析工具,如果是Java程序导致的服务器CPU占用异常,大家可以利用此工具进行排查。
尾巴
作者目前还是小白,JVM性能调优还设计到很多工具。
jstack(查看线程)、jmap(查看内存)和jstat(性能分析)。
等作者用到了会一一发布博客记录。