最近在梳理自己曾经遇到过的一些问题,加深一下印象,温故而知新嘛,嘻嘻~
1. 准备工作
为了能模拟出CPU占用过高的现象,这里我们需要准备一段代码,在代码中实现一段死循环的逻辑(众所周知,死循环是会导致CPU异常高的一种场景),相关代码如下:
public class CpuTooHighTest {
public static void main(String[] args) {
System.out.println("application start"); String str = "hello world!!!"; int i = 0; boolean check = true; while (check) {
//模拟业务逻辑,当符合某种条件时,将check设置为true,结束循环 //这里为了实现死循环,所以直接写死一种永远不可能为true的判断 1==2 if (1 == 2) {
check = false; } i++; } System.out.println("application end"); } }
讯享网
讯享网java -cp cpu_too_high_test.jar CpuTooHighTest &
java -cp 命令可以指定类运行所需要依赖的其他类的路径,一般是jar包、类库之类的;
上面的命令中 cpu_too_high_test.jar 是我打包出来的jar包名称,CpuTooHighTest 是代码中的类名,所以最终会执行CpuTooHighTest 这个类中的 main 函数。
到这里,已经启动了一个存在死循环的程序,并且启动之后可以看到CPU里面飙升到了100(我这里是运行在电脑的虚拟机中)
2. 定位出CPU异常的进程
使用TOP命令,查看当前服务器内所有进程的CPU使用情况
top - 16:04:39 up 3:24, 2 users, load average: 1.15, 1.26, 0.97 Tasks: 108 total, 1 running, 107 sleeping, 0 stopped, 0 zombie %Cpu(s): 99.7 us, 0.3 sy, 0.0 ni, 0.0 id, 0.0 wa, 0.0 hi, 0.0 si, 0.0 st KiB Mem : total, free, used, buff/cache KiB Swap: total, free, 0 used. avail Mem PID USER PR NI VIRT RES SHR S %CPU %MEM TIME+ COMMAND 61001 root 20 0 22888 10492 S 99.3 1.2 18:28.63 java 1 root 20 0 6656 4164 S 0.0 0.4 0:01.20 systemd 2 root 20 0 0 0 0 S 0.0 0.0 0:00.00 kthreadd 4 root 0 -20 0 0 0 S 0.0 0.0 0:00.00 kworker/0:0H 5 root 20 0 0 0 0 S 0.0 0.0 0:00.80 kworker/u256:0 6 root 20 0 0 0 0 S 0.0 0.0 0:00.36 ksoftirqd/0 7 root rt 0 0 0 0 S 0.0 0.0 0:00.00 migration/0 8 root 20 0 0 0 0 S 0.0 0.0 0:00.00 rcu_bh 9 root 20 0 0 0 0 S 0.0 0.0 0:00.77 rcu_sched 10 root 0 -20 0 0 0 S 0.0 0.0 0:00.00 lru-add-drain
很明显,可以发现 61001 这个 java 进程CPU使用率达到了 99.3%,罪魁祸首必然就是它了。
2.找出对应的线程
已经确定了61001这个进程,那我们接下来就可以使用命令找出对应的异常线程信息:
讯享网ps -mp {
pid} -o THREAD,tid,time | sort -rn
将pid替换之后,执行结果如下:
[root@localhost apps]# ps -mp 61001 -o THREAD,tid,time | sort -rn USER %CPU PRI SCNT WCHAN USER SYSTEM TID TIME root 99.4 19 - - - - 61002 00:27:16 root 99.4 - - - - - - 00:27:16 root 0.0 19 - futex_ - - 61010 00:00:00 root 0.0 19 - futex_ - - 61009 00:00:00 root 0.0 19 - futex_ - - 61008 00:00:00 root 0.0 19 - futex_ - - 61007 00:00:00 root 0.0 19 - futex_ - - 61006 00:00:00 root 0.0 19 - futex_ - - 61005 00:00:00 root 0.0 19 - futex_ - - 61004 00:00:00 root 0.0 19 - futex_ - - 61003 00:00:00 root 0.0 19 - futex_ - - 61001 00:00:00
可以发现,有一个线程CPU使用率很高,达到了99.4%,线程ID为61002,已经运行了 27分钟16秒
3.TID转换成16进制
将TID转换成16进制的命令如下:
讯享网printf "%x\n" tid
将tid替换成61002,执行结果如下:
[root@localhost apps]# printf "%x\n" 61002 ee4a
4.使用jstack命令查看进程信息
使用jstack命令,可以查看到进程的信息,通过tid过滤可以更方便的进行查找
讯享网jstack -pid | grep 16进制tid
替换pid、tid之后,执行命令:
[root@localhost apps]# jstack 61001 |grep ee4a "main" #1 prio=5 os_prio=0 tid=0x00007f0 nid=0xee4a runnable [0x00007f026b]
讯享网jstack 61001 > 61001.txt
查看打印出的信息如下:
...... 由于篇幅原因,省略前面部分内容 "Reference Handler" #2 daemon prio=10 os_prio=0 tid=0x00007f0 nid=0xee4c in Object.wait() [0x00007f02546fd000] java.lang.Thread.State: WAITING (on object monitor) at java.lang.Object.wait(Native Method) - waiting on <0x00000000e3806c00> (a java.lang.ref.Reference$Lock) at java.lang.Object.wait(Object.java:502) at java.lang.ref.Reference.tryHandlePending(Reference.java:191) - locked <0x00000000e3806c00> (a java.lang.ref.Reference$Lock) at java.lang.ref.Reference$ReferenceHandler.run(Reference.java:153) "main" #1 prio=5 os_prio=0 tid=0x00007f0 nid=0xee4a runnable [0x00007f026b] java.lang.Thread.State: RUNNABLE at CpuTooHighTest.main(CpuTooHighTest.java:15) "VM Thread" os_prio=0 tid=0x00007f026406e000 nid=0xee4b runnable "VM Periodic Task Thread" os_prio=0 tid=0x00007f02640bb000 nid=0xee52 waiting on condition JNI global references: 5
通过上面tid得到的16进制,定位到关键内容
讯享网"main" #1 prio=5 os_prio=0 tid=0x00007f0 nid=0xee4a runnable [0x00007f026b] java.lang.Thread.State: RUNNABLE at CpuTooHighTest.main(CpuTooHighTest.java:15)
5.代码排查
到这里,我们便可以定位到CPU被 CpuTooHighTest.java 中15行的代码给占用了,也就是说15行前后的代码存在问题,我们再回过头来看看最开始写的测试代码,为了方便查看,这里给每行代码都加上了行号
1 public class CpuTooHighTest {
2 3 public static void main(String[] args) {
4 System.out.println("application start"); 5 String str = "hello world!!!"; 6 7 int i = 0; 8 boolean check = true; 9 while (check) {
10 //模拟业务逻辑,当符合某种条件时,将check设置为true,结束循环 11 //这里为了实现死循环,所以直接写死一种永远不可能为true的判断 1==2 12 if (1 == 2) {
13 check = false; 14 } 15 i++; 16 } 17 18 System.out.println("application end"); 19 } 20 21 }
其中,15行对应的代码为 i++,说明CPU一直在执行这一行代码,这与我们所写的死循环是一致的,到这里问题定位完成,我们只需要将对应的逻辑进行修复,避免出现死循环即可~
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容,请联系我们,一经查实,本站将立刻删除。
如需转载请保留出处:https://51itzy.com/kjqy/21450.html