jvm-内存溢出和cpu使用率突然飙升

46 阅读3分钟

问题

近期有上线,上线之后的一段时间内,总是cpu使用率突然飙升,并且程序自动重启

生产环境出现几个问题

1.  zabbix cpu使用率突然飙升

image.png

2.  日志:内存溢出

image.png 另外,还有日志还打印了慢sql:耗时几十分钟。但是实际直接在客户端执行该sql,速度很快,因为数据很少,不可能出现慢sql的问题

 

原因-先说结论

慢sql只是现象,不是原因

首先是因为内存溢出了,导致系统卡死,所以执行sql看起来很慢,但实际根本不是慢sql的原因

 

cpu突然飙升也只是现象,不是原因

cpu突然飙升的原因是,线程多,且干活的线程多

 

干活多的原因是,要么cpu密集,要么磁盘io密集

 

真正的原因就是看到的内存溢出,这才是本质原因,其他都只是现象和结果

因为内存溢出了,系统卡死,导致做什么都很慢很卡,比如慢sql线程

 

为什么呢?因为内存不够了,就会疯狂gc,cpu都被gc占用了,业务线程啥都干不了,或者很慢,所以才会出现慢sql等现象

 

包括cpu使用率突然飙升,不是因为业务线程干活飙升,而是因为没用的gc

 

===

以上是纯理论层面的

 

具体原因一般还是:

1.  查询数据库数据太多,比如全表查询

我们这次就是这个原因,全表查询,因为业务没有校验非空入参导致的,呵呵

2.  业务代码循环创建太多对象

 

分析过程

生产环境已经配置jvm参数,内存溢出的时候自动生成dump文件

 

使用eclipse内存分析工具分析dump文件

主要是分析

1.  定位到哪一行代码导致的内存溢出

通过线程调用栈,可以定位到是哪一行代码

2.  哪个对象占用太大内存

通过对象大小,可以定位哪个对象占用了太多内存

 

 

截图

image.png

首先是有个对象占用了4个g

 

image.png

然后点击线程调用栈:定位到报错代码行

 

image.png

报错方法

 

image.png

报错代码行

 

 

 

image.png

点击查询是哪个对象占用了这么多内存

 

image.png

定位到是哪个对象占用了大量内存

刚好和前面的代码(线程调用栈)也都对应的上

 

 

具体原因

分析结果是

1.  全表查询

因为业务代码没有校验入参非空,导致全表查询,总共4g,500多万数据

2.  然后再循环创建临时对象

注意,刚才的全表查询虽然已经成功,但是这个时候实际上已经到了临界点,即循环创建临时对象的时候,随时都可能导致内存溢出,何况是500多数据的循环,呵呵

 

 

看代码就知道了

image.png

dump文件6g

eclipse内存分析工具的内存默认只有1g,远远不够,所以启动报错,改为10g

-Xmx10240m

image.png

总结

1.我定位到报错代码行和大对象之后,发现有同事更新了代码和sql

2.这次更新sql加了非空判断,该同事本身是想优化一下代码

3.但是呢,没想到业务代码(以前其他同事写的)没有校验非空,导致反而出了问题,因为之前如果入参是空字符串,那么sql就是没有查询到数据,但是现在直接查询全表数据,因为Sql加了非空判断