以前我们遇到过dubbo无权限写本地注册文件引起的CPU 100%问题,最终排查结果是由一个死循环引起!作为Java后端开发攻城狮,日常开发时不时会遇到一些CPU使用率异常的问题,那么针对这些情况怎么排查?



centos7占用多少内存 centos7内存占用过高_Java

常见能够引起CPU100%异常的情况都有哪些?

1. Java 内存不够或者溢出导致GC overhead limit exceeded。

2. 代码中互相竞争资源导致的死锁。

3. 特别耗费计算资源的操作,比如正则匹配,Java中的正则匹配默认有回溯问题,复杂的正则匹配引起的CPU异常。

4. 死循环引起的CPU高密度计算。

针对第1种,根据Oracle官方资料,GC overhead limit exceeded表示JVM一直在GC导致应用程序变慢,具体量化指标就是JVM执行垃圾回收花费超过98%的时间,但释放出的可用堆内存却少于2%,连续多次(一般5次)GC回收的内存都不足2%的情况下就会抛出此异常。

经过垃圾回收每次释放的内存都少于2%很容易又被新生对象填满,JVM快速进入下一次垃圾回收,无限循环,由此引起频繁的GC长期消耗我们服务器CPU资源,从而使CPU使用率达到100%

我们可以使用-XX:-UseGCOverheadLimit这个参数关闭GC overhead limit exceeded,但这样治标不治本,建议检查应用程序的内存使用是否合理以及是否需要增加堆内存。



centos7占用多少内存 centos7内存占用过高_Java

服务器CPU使用率飙升异常,黄金4步排查法

1. TOP命令找到占用CPU高的Java进程PID

top

centos7占用多少内存 centos7内存占用过高_centos7占用多少内存_03

2. 根据进程ID找到占用CPU高的线程

ps -mp pid -o THREAD,tid | sort -r

centos7占用多少内存 centos7内存占用过高_centos7 内存使用率计算_04

3. 将指定的线程ID输出为16进制格式

printf "%x\n" tid

centos7占用多少内存 centos7内存占用过高_垃圾回收_05

4. 根据16进制格式的线程ID查找线程堆栈信息

jstack pid |grep tid -A 50

centos7占用多少内存 centos7内存占用过高_centos7 内存使用率计算_06

获取到线程堆栈信息就好办了,以上即是采用单线程模拟一个复杂的正则匹配的堆栈示例图,可以看得出线程都在指向regex.Pattern,在生产多线程环境下这个复杂正则匹配会导致CPU利用率奇高。


centos7占用多少内存 centos7内存占用过高_Java_07