JAVA线上事故:递归导致的OOM

最近因为人员离职,接手一个项目,是xxljob的客户端,部署在k8s上,在排查线上工单时,发现了一个问题:

在管理界面上,我惊讶的发现,三个月的时间,2个Pod,每个都重启了近400次,平均每天重启4次+

因为是无交接接手,业务不熟(最头疼),架构也不熟,硬着头皮去摸索,先从打印日志开始。

打了日志后,开始发现一些端倪,job只有开始,没有结束,也即是说,每次调度开始后,没跑完Pod就重启了,以我的经验,Pod重启可能有以下几种可能:

  • 1,资源耗尽,包括CPU耗尽、JVM内存耗尽OOM;
  • 2,心跳检测异常;

可以很快的排除2,首先是Pod是跑了一段时间才重启的,其次是即便是心跳检测异常,大概率是1引起,不太可能是单纯的心跳检测异常。

我首先是超OOM这个方面去排查,最后证明这个方向是正确的。

据我以往使用XXL-JOB的经验,阻塞策略如果配置的是【单机串行】,可能会导致大量任务堆积在客户端,最终导致OOM。

但当前场景不太可能是这个原因,因为配置的是2小时跑一次,最多也才堆积6个任务,事实上,由于Pod频繁重启,根本就没有任务堆积。

据此推断,单次任务的执行导致了OOM。

是因为数据量太大吗?

于是把并行改成串行,并加限制条件,以业务上的最小粒度执行任务,情况并无好转,单个任务仍然会导致OOM,Pod重启。

只能硬着头皮看代码了,非常痛苦,特别是看别人的代码,心里一直在反复念叨:写得真垃圾。倒没太多恶意,只是宣泄一下而已,别人看我的代码估计也会这样想吧,哈哈。

功夫不负有心人,在代码发现了一个递归调用:
在这里插入图片描述
注意看这个函数的前两行,每次调用都把传进来的List集合保存到新的集合对象中,且其中一个集合的size只会增大不会减小,递归的层次是由第二个集合的初始size决定的,悲剧的是,第二个集合是可能很大的,最终导致的结果就是在使用jmap -histo 看到的有2700W+个PromotionListingOverlayPO对象在内存中:

在这里插入图片描述

到此,OOM就一点都不奇怪了。

找到问题了,自然就容易解决,一个双层for循环就搞定了,不知道当初那位同事为什么会这么写。

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

小手追梦

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值