线上有些系统,本来跑的好好的,突然有一天就会出现报警,CPU使用率飙升,然后重启之后就好了。例如,多线程操作一个线程不安全的list往往就会出现这种现象。那么怎么定位到具体的代码范围呢?今天笔者就教大家一个小技巧
这次,笔者准备了一个demo代码,大致线程模型是这样的:
代码下所示:
public class CpuHighExample { public static void cpuHigh() { final List<String> list = new LinkedList<>(); Thread thread1 = new Thread(new Runnable() { @Override public void run() { int count = 1; while (true) { // 构造thread1为消耗很高cpu的线程 count = count + 1; } } }); thread1.setName("thread1"); Thread thread2 = new Thread(new Runnable() { @Override public void run() { while (true) { try { // 构造thread2为消耗很低cpu的线程 Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } } } }); thread2.setName("thread2"); thread1.start(); thread2.start(); } }这个案例一运行,就听见笔者的电脑风扇起飞了,呼呼作响。直接top一下
果然是java进程,占用最高,CPU 100%了(占用了一个核),而其PID是2717,正是我们跑的例子。那么下一步,我们就需要定位到底是那一个线程在耗CPU
top -H Threads toggle Starts top with the last remembered ’H’ state reversed. When this toggle is On, all individual threads will be displayed. Other- wise, top displays a summation of all threads in a process.如man文档所描述,top -H可以打印出线程信息,我们就top -H一下。
图中可以看到,占用最高的线程PID是2727,同时线程名是thread1。
我们知道jstack可以dump出jvm所有线程运行的快照,然后我们就可以通过刚才获取的PID去定位到jstack那个进程。
// 注意,这边用top出来的进程号2717,而不是top -H出来的2727 jstack 2717 > 1.txt由于jstack打印出的线程号是以16进制的形式表现的,所以我们对2727的线程号做一次转换,得到aa7。
然后我们在1.txt中搜索2727,这里用的是less然后进去后搜索,而不是用grep。因为这样比较直观的能看出之前和之后的信息。less下
我们找到aa7后,就直接能发现代码一直跑在CpuHighExample.java第19行上面。
当然了,我们需要多jstack几次,如果每次jstack出来都刚好在这段代码左右,那么基本可以证明,是这段代码导致CPU飙升了。
CPU突然飙升这个问题,我们很容易通过top -H和jstack找到对应的代码范围,这无疑极大的缩小了我们的定位范围。
强大,10k+点赞的 SpringBoot 后台管理系统竟然出了详细教程!
为什么MySQL不推荐使用uuid或者雪花id作为主键?
为什么建议大家使用 Linux 开发?爽(外加七个感叹号)
IntelliJ IDEA 15款 神级超级牛逼插件推荐(自用,真的超级牛逼)
炫酷,SpringBoot+Echarts实现用户访问地图可视化(附源码)
记一次由Redis分布式锁造成的重大事故,避免以后踩坑!
十分钟学会使用 Elasticsearch 优雅搭建自己的搜索系统(附源码)
Java笔记虾 认证博客专家 Spring MySQL Spring Boot 欢迎微信搜索【Java笔记虾】关注我的公众号,号内回复“后端面试”,送你一份精心准备的Java面试题(提纲+解析),后端技术精选每天定时推送优质Java技术博客,可以琐碎时间学点儿东西