java程序占用cpu100%问题查找方案
目录
一、背景
- 一个java程序今天被告知在linux上cpu 100%,一开始有点难以置信,连上去top命令一看还真是一直"稳定"占用cpu100%;还好机子是多核心的,不然就"GG"了。然后我打开idea在本地运行那个程序,一切正常;后面才知道windows和linux(任务管理)不一样。后面选择在linux上检查问题了。这里记录下解决步骤。
windows和linux任务管理的不一样:
默认情况下,top在Linux上运行所谓的IRIX模式,而Windows任务管理器不运行。假设您有4个核心:
IRIX模式打开时,1个完全利用的内核为100%,4个内核为400%。
IRIX模式关闭时,1个完全利用的内核为25%,4个内核为100%。
这意味着默认情况下,top上的Linux将显示一个无限循环为〜100%,Windows将显示为〜25%,这意味着完全相同的事情。可以在顶部使用Shift i运行时切换IRIX模式。这将使数字匹配
二、使用top命令确定是哪个java程序占用高,找到对应pid
- top命令然后输入小写的m,占用cpu最大的就是第一个了。
top - 09:59:48 up 41 days, 22:14, 2 users, load average: 1.12, 1.10, 1.07
Tasks: 175 total, 1 running, 174 sleeping, 0 stopped, 0 zombie
%Cpu(s): 26.8 us, 0.6 sy, 0.0 ni, 72.4 id, 0.0 wa, 0.0 hi, 0.2 si, 0.0 st
KiB Mem : 33.4/32666536 [|||||||||||||||||||||||||||||||||| ]
KiB Swap: 0.0/16449532 [ ]
PID USER PR NI VIRT RES SHR S %CPU %MEM TIME+ COMMAND
10614 root 20 0 4710976 455404 14056 S 100.0 1.4 18:42.23 java
19944 root 20 0 4835164 444860 22456 S 12.3 1.4 130:22.13 java
19812 root 20 0 4815532 396516 21928 S 0.7 1.2 2:42.83 java
26474 root 20 0 10.8g 215284 13644 S 0.7 0.7 52:01.01 java
5611 root 20 0 573920 17144 6004 S 0.3 0.1 5:54.83 tuned
6064 root 20 0 147760 3756 388 S 0.3 0.0 10:13.76 fdfs_trackerd
19706 root 20 0 4822796 402220 22432 S 0.3 1.2 1:02.62 java
19762 root 20 0 4817108 404852 22440 S 0.3 1.2 2:09.45 java
20031 root 20 0 4801696 502096 22456 S 0.3 1.5 0:48.54 java
20076 root 20 0 4815268 382280 21920 S 0.3 1.2 2:50.58 java
20166 root 20 0 3719700 2.2g 13720 S 0.3 7.2 475:04.63 mongod
20260 root 20 0 3189808 1.7g 12664 S 0.3 5.6 397:56.43 mongod
22781 root 20 0 4720796 565004 14176 S 0.3 1.7 5:43.88 java
28209 root 20 0 0 0 0 S 0.3 0.0 0:04.46 kworker/2:0
........ 省略
三、查看Java应用中线程CPU占比
- 找到这个pid
10614
,使用命令top -p 10614 -H
查看应用中的线程情况。
top - 10:07:57 up 41 days, 22:22, 2 users, load average: 1.11, 1.09, 1.06
Threads: 69 total, 1 running, 68 sleeping, 0 stopped, 0 zombie
%Cpu(s): 26.8 us, 0.4 sy, 0.0 ni, 72.6 id, 0.0 wa, 0.0 hi, 0.2 si, 0.0 st
KiB Mem : 32666536 total, 2127136 free, 10375580 used, 20163820 buff/cache
KiB Swap: 16449532 total, 16449532 free, 0 used. 21745244 avail Mem
PID USER PR NI VIRT RES SHR S %CPU %MEM TIME+ COMMAND
10659 root 20 0 4710976 450360 14056 R 99.9 1.4 26:34.05 java
10614 root 20 0 4710976 450360 14056 S 0.0 1.4 0:00.00 java
10616 root 20 0 4710976 450360 14056 S 0.0 1.4 0:03.56 java
10617 root 20 0 4710976 450360 14056 S 0.0 1.4 0:00.05 java
10618 root 20 0 4710976 450360 14056 S 0.0 1.4 0:00.06 java
10619 root 20 0 4710976 450360 14056 S 0.0 1.4 0:00.06 java
10620 root 20 0 4710976 450360 14056 S 0.0 1.4 0:00.06 java
10621 root 20 0 4710976 450360 14056 S 0.0 1.4 0:00.05 java
10622 root 20 0 4710976 450360 14056 S 0.0 1.4 0:00.07 java
10623 root 20 0 4710976 450360 14056 S 0.0 1.4 0:00.06 java
10624 root 20 0 4710976 450360 14056 S 0.0 1.4 0:00.07 java
10625 root 20 0 4710976 450360 14056 S 0.0 1.4 0:00.00 java
10626 root 20 0 4710976 450360 14056 S 0.0 1.4 0:00.00 java
10627 root 20 0 4710976 450360 14056 S 0.0 1.4 0:00.00 java
10628 root 20 0 4710976 450360 14056 S 0.0 1.4 0:00.00 java
10629 root 20 0 4710976 450360 14056 S 0.0 1.4 0:00.00 java
10630 root 20 0 4710976 450360 14056 S 0.0 1.4 0:00.00 java
10631 root 20 0 4710976 450360 14056 S 0.0 1.4 0:00.00 java
10632 root 20 0 4710976 450360 14056 S 0.0 1.4 0:00.00 java
10633 root 20 0 4710976 450360 14056 S 0.0 1.4 0:00.01 java
10634 root 20 0 4710976 450360 14056 S 0.0 1.4 0:00.16 java
10635 root 20 0 4710976 450360 14056 S 0.0 1.4 0:00.00 java
10636 root 20 0 4710976 450360 14056 S 0.0 1.4 0:00.01 java
........ 省略
- 下面又定位到
10659
这个pid
四、查看线程信息
- 要将
10659
这个pid转16进制,数字转16进制的网站 ,https://tool.lu/hexconvert/ 也可以自己写程序,如python使用hex(10659)
。 jstack 10614 |grep -A 50 0x29a3
jstack是jdk内置命令用来分析线程状态的。
"pool-1-thread-1" #23 prio=5 os_prio=0 tid=0x00007f8f363f5800 nid=0x29a3 runnable [0x00007f8ec483f000]
java.lang.Thread.State: RUNNABLE
at com.xx.article.chat.websocket.protocol.ProcessorFileTransfer$1.run(ProcessorFileTransfer.java:60)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)
at java.lang.Thread.run(Thread.java:748)
"DelayQueueMonitor" #22 prio=5 os_prio=0 tid=0x00007f8f35ba7800 nid=0x29a2 waiting on condition [0x00007f8ec4880000]
java.lang.Thread.State: WAITING (parking)
at sun.misc.Unsafe.park(Native Method)
- parking to wait for <0x00000000ca14a858> (a java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject)
at java.util.concurrent.locks.LockSupport.park(LockSupport.java:175)
at java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject.await(AbstractQueuedSynchronizer.java:2039)
at java.util.concurrent.DelayQueue.take(DelayQueue.java:211)
at com.xx.article.chat.queue.DelayOrderQueueManager.execute(DelayOrderQueueManager.java:81)
at com.xx.article.chat.queue.DelayOrderQueueManager.lambda$init$0(DelayOrderQueueManager.java:67)
at com.xx.article.chat.queue.DelayOrderQueueManager$$Lambda$497/838812606.run(Unknown Source)
at java.lang.Thread.run(Thread.java:748)
........ 省略
五、定位具体代码
- 基本上最有用的信息就是这段
com.xx.article.chat.websocket.protocol.ProcessorFileTransfer$1.run(ProcessorFileTransfer.java:60)
- 找到原因了主要问题还是在那个死循环,一直在占用cpu(自己写的垃圾代码,坑)。
六、转16进制的方法主要有以下几种(下面的10659就是pid)
- 1、linux直接运行
printf "%x\n" 10659
- 2、自己写程序,如python使用
hex(10659)
- 3、在线转16进制的网站 ,如https://tool.lu/hexconvert/
- 4、网页上按F12,在Console输入 ,
a = 10659;a.toString(16);