记一次频繁fullgc排查到解决全流程复盘

一、前言:

刚进新公司业务和各种新的中间件、框架实在消耗了太多精力,最近半年没怎么写博客了,后面会逐步会恢复之前节奏,言归正传,接下来分享一个最近遇到的真实案例

二、第一次频繁fullgc

一个阳光明媚的下午,我和我的同事们正苦逼的在小黑屋(项目室)里赶紧急项目,突然一个同事打来电话说我之前一个项目提供的接口大量超时

我:???!!!立刻检查服务器情况,发现应用出现大量fullgc一分种30多次,gc也耗时飙升

当时的情况:

 

 初步判断大量超时是因为频繁fullgc 导致GC耗时过高从而导致接口耗时暴增,由于项目比较老所以没有电话、短信等强预警通知,此时因为已经影响到线上了而且是较为核心服务,所以来不及dump保留现场只能直接重启服务

重启服务后开始排查产生原因:

1.先看是否有异常流量        --没有

2.mq是否有大量消费进入        --没有

3.其他中间件是否正常        --一切正常

4.观察线程情况        --线程数正常,无死锁线程

5.排查是否有job        --因为是下午触发没有任何job还没执行完

6.观察堆内、堆外内存情况        --发生故障时间段内存相对稳定没有暴增情况

堆外内存使用量也是很稳定

 

 7.查看jvm参数配置垃圾回收器用的ParNew+cms分代回收,新老比例1:1,4G内存,看起来也没有什么问题

8.再看看近期是否有上线发现该应用已经好几天每人发布了,进几次发布也都是小改造没啥可疑代码

结论:因为项目时间赶所以也就没继续查,初步定的结论就是最近上的服务太多了,服务器数量较少可能是扛不住,所以先扩容了几台服务器,并且加上了电话、短信等强监控预警

三、第二次频繁fullgc

上次重启、扩容后几天无事发生,紧急项目也做完了,团队开始快乐团建,然后就在团建的某一天阳光明媚的一个上午,大家正在景区游览时,突然接到各种报警,又出现频繁fullgc了,小组成员迅速回到大巴车上开始排查

和之前的情况一样几乎看不出任何问题,不过这次因为发现比较早还没有影响到线上,所以可以先将内存和线程dump下来再重启,不过因为是团建,本着视人为人的原则,老板并没有让我们当时排查,而是等回去后再看看 

四、开始排查fullgc问题

团建结束后第一天上班开始排查这个问题,刚巧当天早上刚到公司就又出现了第三次频繁fullgc这样我可以拿到了两份dump数据,先观察下内存dump的结果

 

 

发现hashmap占比非常的高,说明本次内存泄漏的根本原因是跟hashmap有关

再仔细观察堆内内存使用情况发现即便一致fullgc但是老年代内存仍然持续增长没有任何下降趋势,说明对象引用一直没释放 ,导致频繁fullgc原因找到了,但是具体因为那块代码还是没定位到

开始代码层面排查

1.是否有使用内存缓存,内存缓存大多用hashmap使用不当是最有可能导致内存泄漏的        --不存在

2.是否存在往静态map里持续注入的情况,如单例类被破坏,初始化的配置map被其他地方持续注入等等                --结果也是不存在

排查了一大圈没有定位到,其他大佬也帮忙看了也没有找到,好像是玄学,只好上报风险慢慢排查

五、 找到毒瘤所在

接下来的几天闲下来的时候就会看看,不过频繁fullgc的频率越来越频繁,从之前的四五天已经到了两天一次,发现到只要老年代到了1.3g就会出现,不过一致不知道根本原因在哪

突然有一天看着内存图突然发现老年代的曲线好像也不是稳步上涨的,全天视角只看老年代明显在8-12上涨速度非常快,因为老年代比较大,所以只看某个区间很难发现,而且大家视角都在观察代码情况忽视了这个,所以快速拿出笔和值每半小时记录老年代值,观察增幅,发现7点开始增幅变快,8:30-9点增幅达到顶峰,下午又变缓

拿到了老年代变化趋势的关键数据后,立刻去看下job、接口qps看是否有符合了,果然发现了一个接口qps变化和这个完全一致,看来泄漏就是这个接口导致的

  具体是哪行代码导致的呢,排查发现,这个接口业务是调用阿里云oss文件上传组件生成链接返回前端,逻辑非常简单,做了以下几件事

1.构建组件请求体

2.请求组件拿到链接等数据

3.返回前端

仔细排查发现关键就在于请求组件时有这么一行代码

每次都会new一个OSSClient出来,而这个组件最大的坑就是这个连接是不会释放的,必须主动调用shutdown()才能关闭,这也就是导致泄漏的根本原因

六、解决方案:

问题都找到了解决起来就so easy了,要么就是每次用完关闭连接要么就是改成单例,考虑到该接口qps比较大,所以就用单例来实现,懒汉模式一写完美解决,百度查了下该组件内部用的是池化思想所以单实例不会影响功能 

七、总结

1.写代码时用到第三方组件时一定要注意,最好是仔细看下内部源码和官方文档上的注意事项,如果是比较出名的组件最好查下是否有坑

2.创建对象时要做好评估能用单例的尽量单例掉,避免出现调用量大内存浪费过多,以及内存泄漏的风险

  • 12
    点赞
  • 35
    收藏
    觉得还不错? 一键收藏
  • 8
    评论
评论 8
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值