java CPU消耗过高

CPU消耗过高

常见的消耗CPU场景

  1. 频繁GC,访问量高时,有可能造成频繁的GC、甚至FGC。当调用量大时,内存分配过快,就会造成GC线程不停的执行,导致CPU飙高
  2. 序列化与反序列化,调用量增大的情况下,导致了CPU被打满
  3. 加密、解密
  4. 正则表达式校验,Java 正则表达式使用的引擎实现是 NFA 自动机,这种引擎在进行字符匹配会发生回溯(backtracking)
  5. 线程上下文切换、当启动了很多线程,而这些线程都处于不断的阻塞状态(锁等待、IO等待等)和执行状态的变化过程中。当锁竞争激烈时,很容易出现这种情况
  6. 某些线程在做无阻塞的运算,简单的例子while(true)中不停的做运算,没有任何阻塞。写程序时,如果需要做很久的计算,可以适当将程序sleep下
  7. while(true)导致CPU飙升,死循环会调用 CPU 寄存器进行计数,死循环不会让出 CPU,除非操作系统时间片到期,但死循环会不断向系统申请时间片,直到系统没有空闲时间做别的事情。
  8. 频繁 Young GC引起 CPU 使用率飚升,Young GC 本身是 JVM 进行垃圾回收的操作,会计算内存和调用寄存器
  9. 线程数很高的应用,不一定影响CPU使用率,如果大多数处于等待状态,Runable 和 Running 状态的线程不多,这时 CPU 使用率不一定会高。

排查问题

1. 执行 top -c 命令,找到 cpu 最高的进程的 id

top -c

java CPU消耗过高_第1张图片

2. jstack PID 导出 Java 应用程序的线程堆栈信息

jstack 15244

java CPU消耗过高_第2张图片

在打印的堆栈日志文件中,tid 和 nid 的含义:

  • nid : 对应的 Linux 操作系统下的 tid 线程号,也就是前面转化的 16 进制数字
  • tid: 这个应该是 jvm 的 jmm 内存规范中的唯一地址定位

在 CPU 过高的情况下

  • 查找响应的线程,一般定位都是用 nid 来定位的。
  • 如果发生死锁之类的问题,一般用 tid 来定位。

3. 定位 CPU 高的线程打印其 nid

top -H -p 23395

[root@test03 ~]# top -H -p 23395

top - 17:29:56 up 128 days,  3:59,  5 users,  load average: 0.39, 0.29, 0.32
Threads: 112 total,   0 running, 112 sleeping,   0 stopped,   0 zombie
%Cpu(s):  7.2 us,  1.9 sy,  0.0 ni, 90.7 id,  0.0 wa,  0.0 hi,  0.3 si,  0.0 st
KiB Mem :  8011232 total,   135016 free,  7255296 used,   620920 buff/cache
KiB Swap:  4194300 total,   145072 free,  4049228 used.   478568 avail Mem 

  PID USER      PR  NI    VIRT    RES    SHR S %CPU %MEM     TIME+ COMMAND                                                                                                                                      
15294 root      20   0 4733844 693016  13952 S  1.0  8.7   0:08.90 java                                                                                                                                         
15303 root      20   0 4733844 693016  13952 S  1.0  8.7   0:10.61 java                                                                                                                                         
15306 root      20   0 4733844 693016  13952 S  0.7  8.7   0:09.72 java                                                                                                                                         
15435 root      20   0 4733844 693016  13952 S  0.7  8.7   0:00.97 java                                                                                                                                         
15309 root      20   0 4733844 693016  13952 S  0.3  8.7   0:03.90 java                                                                                                                                         
15380 root      20   0 4733844 693016  13952 S  0.3  8.7   0:01.02 java                                                                                                                                         
15388 root      20   0 4733844 693016  13952 S  0.3  8.7   0:01.10 java                                                                                                                                         
15389 root      20   0 4733844 693016  13952 S  0.3  8.7   0:00.99 java                                                                                                                                         
15396 root      20   0 4733844 693016  13952 S  0.3  8.7   0:01.03 java                                                                                                                                         
15398 root      20   0 4733844 693016  13952 S  0.3  8.7   0:00.99 java                                                                                                                                         
15416 root      20   0 4733844 693016  13952 S  0.3  8.7   0:01.11 java                                                                                                                                         
15430 root      20   0 4733844 693016  13952 S  0.3  8.7   0:01.01 java                                                                                                                                         
15244 root      20   0 4733844 693016  13952 S  0.0  8.7   0:00.00 java                                                                                                                                         
15245 root      20   0 4733844 693016  13952 S  0.0  8.7   0:19.88 java                                                                                                                                         
15246 root      20   0 4733844 693016  13952 S  0.0  8.7   0:00.66 java                                                                                                                                         
15247 root      20   0 4733844 693016  13952 S  0.0  8.7   0:00.60 java                                                                                                                                         
15248 root      20   0 4733844 693016  13952 S  0.0  8.7   0:00.63 java           

由此可以看出占用 CPU 较高的线程,但是这些还不够,无法直接定位到具体的类

nid 是 16 进制的,所以我们要获取线程的 16 进制 ID:

[root@test03 ~]# printf "%x\n" 23395
5b63

然后根据输出结果到 jstack 打印的堆栈日志中查定位:

"Abandoned connection cleanup thread" daemon prio=10 tid=0x00007f05d8031000 nid=0x5b63 in Object.wait() [0x00007f06442fa000]
   java.lang.Thread.State: TIMED_WAITING (on object monitor)
	at java.lang.Object.wait(Native Method)
	at java.lang.ref.ReferenceQueue.remove(ReferenceQueue.java:135)
	- locked <0x00000000c2f83560> (a java.lang.ref.ReferenceQueue$Lock)
	at com.mysql.jdbc.AbandonedConnectionCleanupThread.run(AbandonedConnectionCleanupThread.java:43)

CLC

你可能感兴趣的:(方法论,java,java,堆栈,定位,jvm,linux)