Java程序CPU占用过高排查

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接: https://blog.csdn.net/qq_32099833/article/details/102530908

昨天博客项目突然宕机,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(性能分析)。
等作者用到了会一一发布博客记录。

猜你喜欢

转载自blog.csdn.net/qq_32099833/article/details/102530908