CPU 100%排查及常见案例
目录
这篇文章主要分享一般线上项目遇到CPU%时排查的方式,并提供了几个典型案例来帮助大家熟悉排查过程,我会先以 “死循环” 为例子来为大家演示一遍整体的排查流程
一、排查方式介绍
1.top 命令查看CPU占用100%的进程号(PID)
如果java服务有多个可以通过 ps -aux|grep java 命令来找到对应服务的进程号(PID)
2. top -H -n 1 -p PID 然后通过命令查找对应进程下线程的状态,可以看到3418线程cpu极高
3.然后通过 jstack -l PID > ./jstack.log 命令输出进程的线程文件
注意这里的PID 是进程号 ,这里我是3400
4.查看刚输出的jstack.log文件,查看线程详情
注意这里的线程PID是第二步PID,还要转成16进制
例如:我这里PID就是3418 转成16进制就是 d5a
我是通过vim 命令查看log文件,可以 /+字符串 例如:/d5a 直接搜索所在位置,可以看到此线程正在运行中,且代码行数也标注清楚
二.案例介绍
这里案例都参照上面的步骤来,不再一一演示,只放结果·
1.死循环
/**
* 死循环
* @return
*/
@GetMapping("/deadCycle")
public String deadCycle(){
for(int i=1;i>0;i++){
System.out.println(i);
}
return "Success";
}
2.死锁
正常一个死锁是不会导致cpu 100%的,除非很多线程死锁或者一直自旋获取锁,这里为了演示直接搞了个极端的例子
/**
* 死锁
* @return
*/
@GetMapping("/deadLock")
public String deadLock(){
Lock lock1=new ReentrantLock();
//线程t1中
new Thread(()->{
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
while (!lock1.tryLock()){
System.out.println("线程1 一直自旋获取锁");
}
System.out.println("线程1 获取到锁 do something");
}).start();
// 线程2
new Thread(()->{
lock1.lock(); //此时线程2 获取到锁 但是一直阻塞 导致锁无法释放
while (true){
}
}).start();
return "Success";
}
3.耗时的计算
/**
* 耗时计算
* @return
*/
@GetMapping("/timeConsuming")
public String timeConsuming(){
for (int a = 0; a < 5; a++) {
new Thread(()->{
int i = Integer.MAX_VALUE;
double temp = 0;
for (int j = 1; j <= i; j++) {
temp += Math.pow(j,j-1);
}
}).start();
}
return "Success";
}
4.频繁的FULL GC
这种是内存问题导致的CPU 问题,所以放到之后的内存问题排查里了
使用jmeter工具并发请求
private static ThreadLocal<FullGcTest> threadLocal=new ThreadLocal();
/**
* ThreadLocal内存溢出 测试
* @return
*/
@GetMapping("/fullGc")
public String fullGc(){
for (int a = 0; a < 5; a++) {
//一次性产生5个8m 对象
threadLocal.set(new FullGcTest(new Byte[1024*1024*8]));
}
return "Success";
}