关于jvm:记录一次线上系统OOM问题的解决过程

7次阅读

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

前段时间跳槽了,刚入职没 3、4 个月,我所在的小组次要负责 DSP 零碎,我主攻 DSP 中的 dist-orders 服务

先说一下 DSP 是干嘛的,项目组所在的公司次要是从事医药行业的,在淘宝、天猫、京东 …… 很多渠道都有自家的店铺,他们本人还有一套 ERP,次要是进销存那一套,DSP 就是负责连贯 ERP 和各个渠道之间传递信息的,什么订单啦、库存啦 ……

前几周,leader 收到线上某某某个机子系统 OOM 的邮件,leader 就顺手丢给我,让我去没事的时候去查查

那我间接登堡垒机去服务器上看看,各种乌七八糟命令就开始用,什么 top、jstack、jinfo、jstat、jmap… 后果发现一个都不行,不是命令不行,是我没权限查看 ……

不说我只不晓得该申请什么样子的权限,就算是晓得了,运维也曾经重启完了,那还查个屁

最终心愿只能放在堆转储文件上,堡垒机是能够下载服务器上的文件,奈何文件太大,6G 多,基本下不下来,寻求运维组的共事帮忙,各种发邮件、拉群、最终在我的软磨硬泡下,终于是给到了我

废话不多说,间接上 jdk 自带的 jvisualvm 软件进行剖析,(jvisualvm 在你装置 jdk 的 bin 目录下)

交给 jvisualvm 进行解析剖析,我电脑是 16G 内存,剖析 6G 的堆转储文件,差点没给我电脑送走 ……

这里除了导致 OOM 线程 和 零碎属性之外 没什么太重要的信息
点开 显示零碎属性 发现 JVM 也没设置什么参数(最大堆、最小堆、GC 一些参数等等)
咱们来看 类

发现 char[]和 String 占了大头,双击 char[],进去看看

emmm,不晓得怎么回事有的中央是乱码,而且临时也没看到有用的信息

点过去点过来,看了良久,最终决定换个软件

用 IBM heapanalyzer 试试(下载地址:https://www.ibm.com/support/pages/node/1109955?mhsrc=ibmsearch_a&mhq=heapanalyzer)

是个 jar 包,间接 java -jar -Xmx15g xxx.jar 启动(这里的 -Xmx 多少内存本人定,如果剖析过程中 OOM 就是你给的内存太少),或者你能够轻易写个启动的脚本

将堆转储文件载入进来,最终就是这个样子了

他这里有个 疑似泄露的点,是 DisOrderItemBO 对象,占了 2.8G 内存,约 58.74%

再往后下看 ArrayList,大概猜想就是 ArrayList 装载了太多的 DisOrderItemBO

让他以树结构模式展现:

没跑了,就是 ArrayList 汇合内 DisOrderItemBO 元素太多,看解析是有 1936459 个 DisOrderItemBO 的实例,总共占用了 2G 多内存

看似失去后果了,实则还是不晓得从哪下手,因为 DisOrderItemBO 用到的中央太多了,基本不晓得是哪个中央引发的

于是,我又又又换了一个软件

MemoryAnalyzer(下载地址:https://www.eclipse.org/downloads/download.php?file=/mat/1.12.0/rcp/MemoryAnalyzer-1.12.0.20210602-win32.win32.x86_64.zip)

加载进来就是这个样子了

这里也有一个 疑似内存透露的点,点击去查看,列出了具体的信息:

首先是哪个线程呈现的问题,其次是哪些对象导致的内存增长且回收不掉

发现和上一个软件剖析的后果差不多,都是 ArrayList 汇合内 DisOrderItemBO 元素太多

当初是已知 DisOrderItemBO 对象产生的太多(在一个线程内),且回收不掉,ArrayList 间接就摈弃掉了,因为他自身没问题,只是承载了太多的 DisOrderItemBO 对象,当初我只须要晓得是哪个线程,刚好这个软件能够看(或者前两个也能看,我没找到吧)

http-nio-7210-exec- 9 线程,我没记错的话,应该是 Tomcat 工作线程池的线程吧,当初又能够确定一件事,就是导致 OOM 的必定不是零碎中的异步工作或者是什么 JOB 等等,其实这里曾经给出了答案,怪就怪在我懒,没往下持续看

线程信息外面给出了我的 Service 绝对应的类的全包名以及对应的 controller 的全包名

依据信息间接找到代码,略微捋了一下代码逻辑,在本地启动试试,我去线上日志摸了一个申请报文,用 postman 申请一下,试了几次怎么玩都不会呈现很多 DisOrderItemBO 对象

而后我就想,如果参数为空(本来代码就不会对必填参数校验),我就试了一下,控制台打出 sql 之后,我拿着去线上 DB 中执行这个 sql

去掉不必要的查问列,以及排序,只看个数(一条数据对应一个 DisOrderItemBO 示例),同理如果查出来了后面剖析的 1936459 个示例,那么就对上了

为了谨严,我在 where 条件多了一个创立工夫,工夫截止到这个堆转储文件产生的前 10 分钟(产生 OOM 时产生的堆转储文件会很慢)后果查问进去了 1936374 个条数据,尽管没对上,然而误差也没有很多,当初看来,大差不差就是这里除了问题了

尽管找到了,然而疑难点是,这个接口是查问订单详情,在页面上操作不应该呈现没有必填参数(订单主体 ID)的状况呀,这个疑难我始终没想通 ……

如果过了几周半个月的,我没有更新后续持续排查的文章,就阐明曾经把这个问题完满解决了

正文完
 0