【测试人生】记一次导表检查流程中导致JVM的OOM问题

最近在项目组测试有开发一个导表检查的需求,大致是在策划提交表更新到svn之后,svn发送post-commit到策划表数据服务,而后策划表数据服务下载excel文件,更新数据之后,将导表检查下游服务所需的检查数据进行整合,然后post到导表检查服务。在这个过程中,由于做的仓促没有考虑设计,最后策划表数据服务的JVM发生了OOM问题。经过一番排查改进了设计,解决了这个问题。

JVM的内存结构跟GC流程是老生常谈的话题。Java8去掉了永久区的设定,更改为了Metaspace存储类的元信息、常量等内容,而剩下来依然是新区eden和老区old。当eden区空间满的时候触发young gc,将eden区根节点不可达的对象清除,存活的对象转到survivor区。survivor区的对象如果经历了某一个数(可配置,最高15)的young gc后仍然存活,就会转到old区。如果短时间内创建大量对象,且eden区放不下,young gc没有清除过多数据的情况下,多余的数据会转到old区。如果old区也放不下,就出现OOM(Out Of Memory)。一般业务层面导致OOM的原因基本上是一次产生大量对象,或者是内存泄露,没有及时清除不需要的数据引用。

策划表数据的业务逻辑上是下载数据->更新数据->进行导表检查的一个流程,其中下载、更新数据这一环节会产生大量的对象,而同样进行导表检查时为了发导表检查所需的数据,也会产生大对象——需要将数据序列化为json字符串。在这个流程里自己犯了几个错误导致OOM的问题,具体如下:

  • 导表检查的设计直接采用request数据然后在response里获取导表检查结果的方式,并没有增加回调接口,使得如果导表检查方出现逻辑问题不能及时返回结果的话,发送的导表数据json以及序列化后的结果将不能被gc,导致内存泄漏。因此增加了一个回调接口供导表检查下游调用,使得httpclient对象能够释放,从而request的json数据可以被young gc给消除掉。
  • request接口采用第三方的库,传参是json string,但是在实际post时候会调用getBytes,无形中增加了内存开销。因此直接把第三方库代码扣下来,并且直接序列化json为bytes,减少内存开销。
  • 导表检查前会导入数据,导入数据会不断下载excel文件并提取其中内容,这个步骤有触发young gc的可能。如果某次导入数据之后需要导表检查,就手动申请一次gc(),避免潜在的问题。
  • 导表检查所在的容器规格升级为8G内存,并在jvm启动选项中设定eden区跟老区各一半,survivor区最大总共占1/4的eden区。

最终暂时解决了这个问题,如果后续有其它的优化策略,还要继续补充。


更新:后续找到了内存泄露的原因,是导表过程中缓存大量数据所致,最终修复了这个缺陷。至于JVM方面,一般情况下,基本上也不需要调参的啦~

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

utmhikari

创作不易,共同助力!

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

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

打赏作者

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

抵扣说明:

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

余额充值