最近一个项目二期上线,在测试线有跑过测试,代码是没有什么问题的。但一上生产就出现OOM 的问题,所以进行排查。
一、首先从日志入手
Caused by: java.lang.OutOfMemoryError: Java heap space
at com.alibaba.fastjson.serializer.SerializeWriter.expandCapacity(SerializeWriter.java:290)
at com.alibaba.fastjson.serializer.SerializeWriter.writeStringWithDoubleQuote(SerializeWriter.java:870)
at com.alibaba.fastjson.serializer.SerializeWriter.writeString(SerializeWriter.java:2113)
at com.alibaba.fastjson.serializer.StringCodec.write(StringCodec.java:46)
at com.alibaba.fastjson.serializer.StringCodec.write(StringCodec.java:35)
at com.alibaba.fastjson.serializer.MapSerializer.write(MapSerializer.java:270)
at com.alibaba.fastjson.serializer.MapSerializer.write(MapSerializer.java:44)
at com.alibaba.fastjson.serializer.ListSerializer.write(ListSerializer.java:137)
at com.alibaba.fastjson.serializer.JSONSerializer.write(JSONSerializer.java:281)
at com.alibaba.fastjson.JSON.toJSONString(JSON.java:673)
at com.alibaba.fastjson.JSON.toJSONString(JSON.java:611)
at com.alibaba.fastjson.JSON.toJSONString(JSON.java:576)
从报错日志中捞到了关于阿里的 fastjson 的错误,想起之前 fastjson 爆出过 toJSONString 的时候发生 OOM 的情况 ,随即排查版本发现我们使用的版本是 1.2.47 版本,这个版本确实有这个问题,便将 fastjson 版本升级为最新的 1.2.62 重新测试。
在更新版本后仍然出现Caused by: java.lang.OutOfMemoryError: GC overhead limit exceeded的问题
这次排查日志没有发现fastjson的相关报错,也没有任何有用信息….所以换一种方法。
二、分析堆栈的dump文件
因为日志文件查不出可用信息了,所以决定排查一下程序堆栈的dump文件。 这里要用到一个命令来生成 Java 程序堆栈的 dump
- jmap -dump:format=b,file=/data/heapdump.hprof 进程id file 后跟的是生成文件的目录, heapdump 是生成的文件名.
生成后使用了Eclipse Memory Analyzer 工具分析 dump 文件 , 下载后通过点击 File->Open Heap Dump 打开保存下来的 heapdump.hprof 文件(后缀需要 .hprof , 否则找不到要打开的文件)

按照默认的使用

这里可以看到某个线程占用了 2.6GB 的内存,

通过查看具体细节找到了是数据库连接耗费了大量资源,便对代码中数据库操作逐一排查,并检查每次连接是否正常关闭,因为我们项目使用的是某一国产数据库,所以排查难度比 MySQL 更大了….
最后找到代码确实有一处连接未正常关闭,但修改代码后还是出现了 OOM ,最后通过每处的 sql 排查,找到最后的根本原因是:我们生产库被其他部门做压测,堆积了大量无效数据,单表数据量有两千多万行,查询时已经爆出查询结果集过大,Java 虚拟机内存溢出…..
三、原因总结
结合我们项目的情况,我们遇到的 OOM 主要有3个情况
- 1.fastjson 低版本未更新, 导致 OOM, 版本更新即可
- 2.数据库连接未正常关闭,在大量数据库操作时造成资源浪费
- 3.生产库的压测数据没有及时删除,造成我们测试出现问题….

本作品采用知识共享署名-相同方式共享 4.0 国际许可协议进行许可。