码迷,mamicode.com
首页 > 其他好文 > 详细

OSSClient引起的内存泄漏

时间:2018-05-08 12:11:27      阅读:3153      评论:0      收藏:0      [点我收藏+]

标签:导致   转储   线程   输出   suspect   http   cpu   9.png   构造   

最近公司的服务总是时好时坏,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引起的内存泄漏

标签:导致   转储   线程   输出   suspect   http   cpu   9.png   构造   

原文地址:https://www.cnblogs.com/cbzj/p/9007260.html

(0)
(1)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!