OSSClient引起的内存泄漏

Posted cbzj

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了OSSClient引起的内存泄漏相关的知识,希望对你有一定的参考价值。

最近公司的服务总是时好时坏,CPU和内存经常会占用到100%,导致服务不可用,重启之后就好了,但是过一段时间又会出现同样的情况,因此怀疑是出现了内存泄漏。没办法,只能一步步分析看问题出在哪里。

第一步

找到进程的端口号 ps -ef | grep XXX,其中XXX代表该进程的关键字。
使用 jmap -histo:live port | head -10 初步找出占用内存最大的对象,但是由于本次泄漏找到的对象比较奇怪,因此需要更加细的来找到泄漏的对象。

第二步

使用 jmap -dump:live, format=b, file=heap.hprof port 将该进程的堆转储到文件,file的值表示转储后的名字,live是可选项,如果输入则表示只输出活的对象到文件。

第三步

将堆转储文件下载到本地电脑,利用工具进行分析。在这里我推荐 Eclipse 的 MAT 分析工具。分析完成后如下图所示:
技术分享图片
这里重点关注 Leak Suspects, 打开后如下图所示:
技术分享图片
MAT指出了可能存在内存泄漏的情况,点击 Details查看详情:
技术分享图片
可以很清楚的看到存在大量的 org.apache.http.impl.conn.PoolingHttpClientConnectionManager 对象,存放在同一个ArrayList当中,并且被 com.aliyun.oss.common.comm.IdleConnectionReaper 实例持有。

第四步

分析 IdleConnectionReaper 源码:
?技术分享图片
该类继承自 Thread,且在类加载过程中就会初始化一个 ArrayList 实例。和分析报告吻合,但是当我想要查看究竟是哪里使用了这个类时却无法准确定位到。于是我想到从创建OSSClient对象开始查找。
从最初的创建OssClient对象开始查找,最后定位到
??技术分享图片
该方法,项目中使用的创建方式为 DefaultServiceClient,进入该构造方法:
?技术分享图片
由于默认配置是使用 IdleConnectionReaper 来管理过期连接,因此进入到这个方法中:
?技术分享图片
技术分享图片
可以看到,OSS客户端专门建立了一个线程来管理其所需要的HTTP连接。而在业务中每次都会创建一个新的OSS客户端对象,那么每次也都会往该List中添加新的连接。由于这些连接对象一直被持有,所占用的内存无法释放,越到后面所创建的对象越多,占用的内存越大,一直到内存被使用完为止。
同时我可以联想到,应该有一个方法来手动释放掉已使用的连接,回到OSSClient,有一个 shutdown 方法:
技术分享图片
技术分享图片
将本次创建的Http连接对象从管理队列中移除,并且关闭。

总结

找到问题可能的原因以后,我在本地模拟线上不停创建OSSClient的场景,然后分析堆转储文件,MAT 给出的结论是一致的,同时在调用创建对象后再调用 shutdown 方法,内存不再不停的增长。






















以上是关于OSSClient引起的内存泄漏的主要内容,如果未能解决你的问题,请参考以下文章

如何消除其他库引起的内存泄漏?

如何使用模块化代码片段中的LeakCanary检测内存泄漏?

Release编译模式下,事件是否会引起内存泄漏问题初步研究

android中handler使用应该注意的问题(解决由handler引起的OOM内存泄漏)

避免android片段中内存泄漏的最佳方法是啥

内存泄漏