背景:
之前做了一个小型的项目,功能比较简单,大致是从aliyun的oss上下载文件,然后把文件传输给一个HTTP服务。
问题:
项目的下载文件和调用HTTP服务的频率约为10W每月。项目上线一个多月之后,生产出现了一次OOM。
分析过程:
1. 对生产的JVM进行dump,看了下leak suspect。发现有大量的PoolingHttpClientConnectionManager对象没有被回收,数量和文件下载次数基本一致。
2. 在项目代码中查了下这个类,发现这个类属于httpclient包,查看了下项目中的使用httpclient的地方,怀疑自己的使用方式有问题。按照httpclient官网的example改写了httpclient工具类。再次上生产去执行,发现Young GC之后,PoolingHttpClientConnectionManager还是没有被回收,老年代的空间一直在增长。
3. 回收仔细思考了下,应该查询到底是什么对象持有这些类的引用,导致对象没有被回收。
4. 查看了GCroot到这些对象的引用链关系,发现被一个oss的相关对象所持有。
5. 分析了下oss相关的代码,发现oss也依赖了httpclient,并且项目中使用oss的地方,没有将ossClient进行shutdown,导致资源一直没有被回收。修改了oss相关代码,文件下载完毕后,调用OSSClient.shutdown。再次上生产执行,每次Young GC之后,对象被回收,老年代基本不再增长。