关于java:记一次oom问题排查

7次阅读

共计 1547 个字符,预计需要花费 4 分钟才能阅读完成。

大家好,我是大彬~

明天给大家分享最近呈现的 OOM 问题。

上周五早上,测试同学反馈测试环境的子系统服务始终超时,申请没有响应。

收到这个问题之后,我有点纳闷,最近这个零碎也没有改变代码逻辑,怎么会忽然报服务超时的问题。为防止影响测试进度,我连忙登陆堡垒机查看日志,看看到底啥状况。

首先先看零碎负载状况,应用 top 命令查看。发现其中某个 Java 过程 cpu 始终继续停留在 100% 到 200% 之间。因为这个零碎不波及大量运算的逻辑,所以能够猜到要不就是死循环的问题,要不就是频繁 full gc 导致。

查看系统日志发现,呈现java.lang.OutOfMemoryError: Metaspace,很显著,元空间内存溢出了。

接着查看零碎 gc 状况,应用以下命令查看。pid 为对应的 Java 过程 id,通过 top 命令获取。参数 1000 示意每隔 1000ms 打印一次记录。

jstat -gc pid 1000

一看执行后果,果不其然,full gc 从应用程序启动到采样时曾经触发了几百次!这也是 cpu 始终 100% 的起因。

其中还有另一个参数 MC(元空间分配内存大小),曾经靠近设置的最大元空间大小(配置的 –XX:MaxMetaspaceSize=128m)。

这里也简略介绍下元空间。

元数据是 jdk8 里特有的数据结构,jdk7 是叫永恒代,到了 jdk8 永恒代就废除了,应用元空间代替。元空间被调配在本地内存中(非堆上),默认不限度内存应用,能够应用 MaxMetaspaceSize 指定最大值。

元空间由两大部分组成

  • Klass Metaspace,用来存 klass 的,klass 是 class 文件在 jvm 里的运行时数据结构。
  • NoKlass Metaspace,专门来存 klass 相干的其余的内容,比方 method,常量池等,这块内存是由多块内存组合起来的。

MC 就是 Klass Metaspace 以及 NoKlass Metaspace 两者总共调配的内存大小,单位是 KB。上图中,MC 曾经靠近元空间设置的上限值,也就是此时元空间内存曾经不够用了,导致始终触发 full gc。

而后就是 dump 内存进行剖析,看看是什么起因导致的元空间内存溢出。应用命令./jmap -dump:live,format=b,file=/xxx 导出内存 heap 到 xxx 地位(hprof 格局),而后应用 MAT 工具进行剖析。

将 hprof 文件导入 MAT 工具,关上内存透露剖析(波及公司外部源码,所以打了马赛克):

看到这个之后,就大略晓得是什么问题了。因为最近公司外部在推广一个破绽监控工具,须要在服务端部署 agent 程序,这个工具会收集、监控利用程序运行时函数执行、数据传输,能够辨认常见的平安缺点和破绽。而打码的局部正是这个破绽监控工具的利用包名,很可能是引入这个工具引起的问题!

进一步确认问题。关上 Histogram:

Shallow Heap 代表一个 对象构造本身 所占用的内存大小,不包含其属性援用对象所占的内存。

Retained Heap 是一个对象被 GC 回收后,可开释的内存大小,等于开释对象的 Retained Heap 中所有对象的 Shallow Heap 的和。

在 Histogram 视图中,选中其中一个类点击鼠标右键会弹出一个菜单,抉择 Merge shortest paths to GC Roots,查看以后对象到 GC Root 的门路,能够过滤一些类型的援用。

后果如下:

占用内存空间最多的就是破绽监控工具的类,也根本能够确定问题所在了。

最初把这个破绽监控工具去掉之后,重新部署之后,就不会呈现服务超时的问题了。

以上就是本期 OOM 问题剖析的整个过程~


码字不易,如果感觉对你有帮忙,能够 点个赞 激励一下!

我是程序员大彬,专一 Java 后端硬核常识分享,欢送大家关注~

本文由博客一文多发平台 OpenWrite 公布!

正文完
 0