OssClient导致内存泄漏

图片为证

图片上为问题代码


问题代码.jpg

1.代码解读

一句话解读:通过oss sdk获取oss私有图片临时链接

2.问题发现

  • 日常巡检

    • 发现sentinel后台服务实例pod有掉线情况
    • k8s后台确认服务异常,超过设置弹性伸缩指标
  • 阿里后台

    • fullgc频繁(新服务上线后未关注)
    • cpu、负载间断升高(fullgc引起)
    • 项目重启后内存持续升高(途中几段都为重启后运行)


      阿里后台发现1.jpg
    阿里后台发现2.jpg

3.解决过程

  • 1.根据阿里后台现象判断有明显内存泄漏
  • 2.找运维同学查看jvm指标,导出dump文件
查看堆中内存占用最大的对象,同时触发手动FullGC 
jmap -histo:live |head
导出dump文件
jmap -dump:format=b,file=name.hprof 
  • 3.后让运维同学重启服务并升级服务配置:1c2g->2g4G,避免短期频繁触发fullgc、触发弹性伸缩
dump文件分析

我使用的是jprofiler破解版,导入即可查看离线jvm堆栈信息

  • 1.jvm堆中实例数排序


    实例数排序.jpg
    • 开始我一直在关注这个排序结果,最多的实例为HashMap$Node,是个反射对象
    • 继续查看对象根实例,发现很凌乱,根里面什么信息都有,看不出哪里内存泄漏
    • 根据上面的结果初步判定是代码中序列化出现了内存泄漏(关注的点和判断结果导致排查方向错误)
    • 于是去排查了代码(不知道哪里的问题,尝试解决)
      • 线程池核心线程配置不符合实际
      • 发现fastjson和参考服务版本不一致,网上也有类似案例:序列化要配置,全局共享实例SerializeConfig.globalInstance
      • restTemplate未指定连接池
    • 调整线程池、升级fastjson版本、指定restTemplate连接池,处理后上线,观察后并未得到解决
    • 反查了fastjson两个版本1.2.58,1.2.62,已经默认是全局共享实例了(改这个版本实际啥用也没有)


      fastjson1.jpg
    fastjson2.jpg

    - ======================================================
    - 前面所有尝试无效后,又去查代码,发现可疑代码片段(见开头)
    - 经过优化ossclient为单例、测试,初步定位就是oss连接无限创建,没有关闭导致的内存泄漏


    优化代码.jpg

    - 引发了疑问:jprofiler为啥看不出是http连接池问题导致内存泄漏?下图是找同事eclipse MAT分析查看结果:直接指出了问题所在


    eclipse1.jpg
    eclipse2.jpg
  • 2.jvm堆中保留对象排序


    保留对象排序.jpg
传入引用gc根.jpg
祸根.jpg
  • jprofiler点击【保留大小】排序,其实也很容易发现问题,常见对象一般先忽略,可见异常对象:PoolingHttpClientConnectionManager
  • 点击【显示到GC根的路径】,PoolingHttpClientConnectionManager整个大对象被一个数组对象引用着的,根路径为:com.aliyun.oss.common.comm.IdleConnectionReaper
  • IdleConnectionReaper里面有个【静态数组】对象,就是用来放连接对象的,问题代码刚好未关闭连接,导致无限增长

4.总结

  • 1.内存泄漏本身不是特别难处理的问题,解决过程一般来说都是固定程序(当然,也会遇到排除特别难发现的)
  • 2.熟悉相关分析工具能事半功倍,案例中我就是因为不熟悉工具导致盲目尝试过,但是盲目过程中也优化了部分代码

5.思考

本次内存泄漏是ossclient连接无限创建并未关闭导致,为什么从jprofiler看HashMap$Node实列数非常大?

你可能感兴趣的:(OssClient导致内存泄漏)