内存溢出OOM的问题排查流程

一、事件简述:

          之前的项目部署在物理机上手动部署,现在需要将其虚拟化在虚拟机上部署,结果发现频繁出现OOM如图:

内存溢出OOM的问题排查流程_第1张图片

二、排查过程:

1.  虚拟机部署的环境采用套餐为s, 单核cpu, 容器内存大小为2G, 启动脚本中jvm内存限制为 1G*10/8,启动JVM参数为 

work       932     1  4 13:34 pts/1    00:13:16 /home/work/emcjdk11/runtime/bin/java -Xms816m -Xmx816m -Xdebug -Xrunjdwp:transport=dt_socket,server=y,address=127.0.0.1:8139,suspend=n -server -Xss320K -XX:+UseG1GC -XX:MetaspaceSize=1024m -XX:+PrintGC -verbose:gc -Xloggc:log/gc.log -Djava.io.tmpdir=log/temp -Dserver.port=8138 -Dmanagement.server.port= -Dformula.launcher.framework-path=/home/work/emclauncher/runtime/lib/formula-framework.jar -Dformula.launcher.application-path=lib/compass-server-app.jar -jar /home/work/emclauncher/runtime/lib/formula-launcher.jar

2. 怀疑是线下环境资源设置过低,进行容器升级,所以采用大套餐。8核 容器内存大小为20G. 实际jvm限制 16G, 启动JVM参数为

work     26525     1  7 16:15 pts/0    00:12:47 /home/work/emcjdk11/runtime/bin/java -Xms16384m -Xmx16384m -Xdebug -Xrunjdwp:transport=dt_socket,server=y,address=11394,suspend=n -server -Xss320K -XX:+UseG1GC -XX:MetaspaceSize=256m -XX:+PrintGC -verbose:gc -Xloggc:log/gc.log -Djava.io.tmpdir=log/temp -Dserver.port=11393 -Dmanagement.server.port= -Dformula.launcher.framework-path=/home/work/emclauncher/runtime/lib/formula-framework.jar -Dformula.launcher.application-path=lib/compass-server-app.jar -jar /home/work/emclauncher/runtime/lib/formula-launcher.jar

3. 经过多人并发请求,不一会就又OOM。 gc日志如下:

内存溢出OOM的问题排查流程_第2张图片

 4. 这个肯定不是配置能解决的问题,应该是系统内存泄漏或者其他原因,深入排查,先看原来的物理机上的使用情况 (原先线上5台物理机),发现线上单机java进程占用内存为17G. 明显不符合业务场景。单日请求不超过2W. 单机请求不超过5k

5. 深入排查,jmap -dump:live,format=b,file=heap.bin 26525  将当前的dump文件 导出,并通过mat进行分析。 (由于文件过大,目前导出正常请求时候的dump文件)。 由于线程很少(40+),基本排除多线程引起,初步判断大对象的问题,先看看大对象有哪些。

内存溢出OOM的问题排查流程_第3张图片

不看不知道,一看吓一跳,居然有几百M的大对象,我们需要一步步进行处理

 5.1  com.mysql.jdbc.JDBC42ResultSet @ 0x40da072f8  占用233M, 单次查询(单个对象24Byte, 一共居然返回了182W+的数据加载在内存)

内存溢出OOM的问题排查流程_第4张图片

 继续跟进,通过不断的排查引用的对象,发现执行Sql如图:内存溢出OOM的问题排查流程_第5张图片

SELECT meg_trade_name_1st_2b as meg_trade_id_1st_2b, meg_trade_name_1st_2b, meg_trade_name_2nd_2b as meg_trade_id_2nd_2b, meg_trade_name_2nd_2b FROM xxxxx WHERE (ucid = xxx AND post = '销售总经理')

直接查询果然出问题了,返回了几十万个数据,怎么会出现这种事情呢? 继续跟进,发现业务逻辑出问题了  meg_trade_name_1st_2b 写错成meg_trade_id_1st_2b 

内存溢出OOM的问题排查流程_第6张图片

 5.2  java.lang.Thread  java线程的引用堆166MB

内存溢出OOM的问题排查流程_第7张图片

发现一个大的list对象。继续看里面的信息,发现还是第一个sql导致,在 mysql将数据序列化成 list 对象,又建了166MB 的对象。5.1+5.2= 400M大小

5.3 com.mysql.jdbc.JDBC42ResultSet @ 0x41ef36bd8 占用内存64.9M 

内存溢出OOM的问题排查流程_第8张图片

 同样的方法排查,发现sql为select post as post, post as post_name from xxx where ucid = xxx  返回60W数据

进一步排查发现逻辑问题:未去重

三、总结:

  频繁的占用大内存,会导致频繁的gc,影响性能,同时也浪费资源。后端服务上jarvis后 内存限制未16G,所有的数据接口必须控制结果的数据量,理论上加载在内存中的数据量不能超过1W. 

mat 内存分析工具下载   Eclipse Memory Analyzer Open Source Project | The Eclipse Foundation

dump 文件下载 jmap -dump:live,format=b,file=heap.bin 进程号

线上:线程分析,可利用jarvis 的 应用诊断功能 JSTACK分析

你可能感兴趣的:(java)