0%

Java CPU占用率高排查

根据进程id查询CPU占用高的线程id,通过jstack指令查询那些线程都在干什么。

top结果如下

1
2
3
4
5
6
7
8
top - 10:27:39 up 41 days, 22:14,  5 users,  load average: 58.40, 56.51, 56.18
Tasks: 425 total, 2 running, 417 sleeping, 6 stopped, 0 zombie
%Cpu(s): 98.4 us, 0.5 sy, 0.0 ni, 0.9 id, 0.0 wa, 0.0 hi, 0.1 si, 0.0 st
KiB Mem : 13177848+total, 570344 free, 19024560 used, 11218358+buff/cache
KiB Swap: 4194300 total, 2725940 free, 1468360 used. 11207128+avail Mem

PID USER PR NI VIRT RES SHR S %CPU %MEM TIME+ COMMAND
20620 sync360 20 0 28.8g 8.9g 8732 S 3114 7.1 20602:36 java

查询CPU占用较高的进程,可以在进入top界面后,依次敲下 x,y,b键。然后结合 shift+< 或者 shift+> 向左或向右切换排序列

拿到进程id 20620 后查询哪些线程CPU占用高

1
2
3
4
5
6
7
8
9
10
11
[root@app72 tmp]# ps -mp 4611 -o THREAD,tid,time  | grep -v '0.0'
USER %CPU PRI SCNT WCHAN USER SYSTEM TID TIME
apache 743 - - - - - - 35-20:54:30
apache 0.4 19 - futex_ - - 4631 00:32:54
apache 2.0 19 - futex_ - - 4708 02:24:18
apache 0.1 19 - ep_pol - - 4905 00:10:14
apache 31.7 19 - - - - 5013 1-12:46:18
apache 43.1 19 - - - - 5071 2-01:58:49
apache 7.2 19 - - - - 5076 08:26:19
apache 6.3 19 - - - - 5077 07:20:21
apache 38.6 19 - - - - 5101 1-20:45:34

列出了所有 CPU占用不为0的线程相关信息。最后一列是线程在CPU上运行的累计时间(不是存活时间)。

拿到线程id就可以去jstack里看调用栈了。

这里有两点要注意:

  1. jstack 里保存的线程id都是十六进制的,因此需要转换一下
  2. 执行 jstack 必须要用 java进程运行的用户来操作。如:su apache

最后查出该线程调用栈最近100层,部分结果如下:

1
2
3
4
5
6
7
8
[sync360@app72 tmp]$ jstack 4611 | grep -A 100 $(printf "%x" 5262)
"XNIO-2 task-215" #388 prio=5 os_prio=0 tid=0x00007f95a0026800 nid=0x148e runnable [0x00007f96825e3000]
java.lang.Thread.State: RUNNABLE
at org.apache.commons.collections4.map.AbstractReferenceMap.purge(AbstractReferenceMap.java:416)
at org.apache.commons.collections4.map.AbstractReferenceMap.purge(AbstractReferenceMap.java:384)
at org.apache.commons.collections4.map.AbstractReferenceMap.purgeBeforeRead(AbstractReferenceMap.java:361)
at org.apache.commons.collections4.map.AbstractReferenceMap.get(AbstractReferenceMap.java:245)
at org.apache.shardingsphere.core.parse.cache.SQLParseResultCache.getSQLStatement(SQLParseResultCache.java:54)

看了多个线程的调用栈,发现共同点是 shardingsphere 的调用。

搜了一下发现是已提交的bug,新版本修复了,升级版本就好了。