一次线上OOM过程的排查


https://blog.csdn.net/qq_16681169/article/details/53296137

一.出现问题

在前一段时间日常环境很不稳定,前端调用mtop接口会出网络异常或服务不存在的异常。查询了服务器上的HSF会有偶尔挂死的情况,服务器上的接口服务都不可用。于是我们对服务器上的状况进行了排查。

文档链接
2. gcore 出现了这个问题后,再其他同学的提醒下,我们尝试了gcore。在排查问题的时候,对于保留现场信息的操作,可以用gcore [pid]直接保留内存信息,这个的执行速度会比jmap -dump快不少,之后可以再用jmap/jstack等从core dump文件里提取相应的信息。

  • a 先生成core dump 主要命令有
sudo gdb -q --pid //启动gdb命令
(gdb) generate-core-file //这里调用命令生成gcore的dump文件
(gdb) gcore /tmp/jvm.core //dump出core文件
(gdb) detach  //detach是用来断开与jvm的连接的
(gdb) quit  //退出
  • 1
  • 2
  • 3
  • 4
  • 5
  • b 把core文件转换成hprof
    jmap -dump:format=b,file=heap.hprof /opt/taobao/java/bin /tmp/jvm.core
    这样就可以使用可视化的内存分析工具来一探究竟了

  • c 使用性能分析工具对hprof进行分析
    这里主要使用了2个工具:一个是 MAT,一个基于Eclipse的内存分析工具,它可以快速的计算出在内存中对象的占用大小,看看是谁阻止了垃圾收集器的回收工作,并可以通过报表直观的查看到可能造成这种结果的对象。第二个是zprofile(阿里内部工具)。直接上图

MAT上的图
这里写图片描述
这里写图片描述

zprofile上的图
这里写图片描述
这里写图片描述

通过图中我们可以发现ali-tomcat的StandardClassLoader类加载器的Retained Size(当前对象大小+当前对象可直接或间接引用到的对象的大小总和)占用了内存的44.21%。并且类加载器的个数高达3212个。于是我们推测可能是ali-tomcat的StandardClassLoader的类加载时出了问题,导致引入的byte[]数组占用的堆大小过多,而Full GC回收不过来,导致了OOM。

5.通过tomcat查明真相

因为怀疑问题出现在StandardClassLoader,于是我们去查看了tomcat的日志,在Catalina引擎日志文件catalina.log找到了一些异样的报警和报错:
这里写图片描述
上面提示加载类时可能会有内存泄露。然后在tomcat的类加载过程中还出现了加载javassist.jar包出现了EOFException。后来拉进了中间件部门ali-tomcat的开发人员一看,原来是我们那个版本的ali-tomcat的会出现这样的问题,要升级新的版本问题就能解决。