前段时间跳槽了,刚入职没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)的情况呀,这个疑问我一直没想通......
如果过了几周半个月的,我没有更新后续继续排查的文章,就说明已经把这个问题完美解决了