程序员

一次内存泄漏问题回顾

2019-10-14  本文已影响0人  没有笔的Monkey

问题现象:

运维通过内存监控发现,应用内存在每次跑批时会在短时间内(5分钟内)飙升10%左右(8G内存),且内存不会下降。

分析过程:

  1. 通过分析对应时间点的日志,分析可能是某个业务跑批导致,但查看代码并未能发现可能存在泄漏的地方;
  2. 通过代码扫描工具找到可能存在文件流未关闭的代码,修复后上线验证问题仍然存在,并无太大效果;
  3. 在内存飙升后,向运维申请生成JVM dump文件(起初运维不愿提供,来回折腾了一段时间);
  4. 使用MAT工具,结合代码分析dump文件:
    4.1 应用进程使用了5-6G内存,而dump文件只有1G左右、通过MAT查看堆内存只有200MB,怀疑是堆外内存泄漏;
    4.2 通过dump文件分析,发现MyBatis部分SQL缓存对象达到几十MB,查询SQL有优化空间,但不会造成很大内存泄漏;
  5. 往堆外内存泄漏方向排查
    5.1 通过MAT工具分析发现存在大量Finalizer对象、ByteBuffer对象;
    5.2 Finalizer对象持有大量OpenSsl对象(27万个),该OpenSsl为Apache加解密包里的类;
    5.3 定位到解密代码有用到ByteBuffer和CryptoCipher类;
    5.4 发现解密代码while循环,会循环创建CryptoCipher和ByteBuffer对象,每次跑批解密的文本数据量达到27万条,问题基本确认;
  6. 优化
    定位到问题后,接下来就好办了。优化代码,CryptoCipher对象和ByteBuffer对象复用。上线后观察多日,跑批后再无内存飙升现象,搞定收工!

总结

本次内存泄漏,从问题出现到定位到问题原因拖了较长时间。主要有如下几个原因:

参考链接:

一次堆外内存泄露的排查过程
Java内存泄漏的排查总结
java.lang.ref.Finalizer占用高内存

上一篇 下一篇

猜你喜欢

热点阅读