记一次FastJson使用不当导致频繁Full GC排查

  具体原因为:https://www.cnblogs.com/liqipeng/p/11665889.html 与这篇文章的情况类似,可以直接按这篇文章的解决方案进行调整,此处只记录下排查过程。

  近期,测试压测某个查询接口时,发现压测的开始一段时间TPS比较稳定,在压测进行多了几次后,TPS开始出现巨大波动。

  进服务器利用TOP命令查看机器基本情况,发现业务层CPU的占用已经达到93%,但数据库层的CPU占用却仅在25%,说明数据库压力并不大,而这个业务只是单纯的查询用户是否处于黑名单状态中的单表查询,也没有看到有慢SQL的记录。

  又发现JVM进程的内存占用已经达6.3g,十分异常,但没有oom的情况出现(也有可能有,当时没注意)。于是转而利用jstat -gcutil命令查看jvm中各区占用内存情况。发现olden区占用在100%,并且在频繁的fullgc,fullgc完olden区的占用又变成100%。

  将项目重启后,继续利用 jstat -gcutil  pid 1000 重新观察各区内存使用情况,发现压测开始后 olden区 的占用在慢慢的爬升,但这个查询接口不应该有什么对象可以晋升到老年代,其中并没有做任何的本地缓存。JVM参数 -Xmx5866m -Xms5866m -Xss256K,那么按照新老年代占用比例为1:2,也不应出现Survivor区内存不足频繁分配到 olden区 的情况,应该说从业务代码来分析进入Survivor区的对象应该是没有的或极少的。(排查过业务代码,并没有死循环new对象情况)

 

  在没有任何头绪的情况下,只能考虑dump下内存进行分析了。这里用了jvisualvm在本地进行模拟。

  在本地将项目的堆内存调至128M,方便快速复现。在本地用20个线程进行并发,跑了1、2分钟就复现出了问题。

 可以看到运行几分钟后,老年代内存就占满了,并且在频繁的GC操作,复现了问题,本地看日志报出了oom。

 dump下内存发现,大量的String对象其内容为 ApiResultxxx,查看其引用对象,发现是Type对象,再往上找发现是com.alibaba.fastjson.parser.deserializer.JavaBeanDeserializer 对象

  由于我们业务层和数据库层是分离的,通过feign客户端进行调用,decode采用fastjson进行处理,这时候只能怀疑到平台组对这一层的decode封装是否有问题。

  排查平台组写的decode源码发现,在ms层直接返回非ApiResult封装的对象时,每次解析都会new一个ParameterizedTypeImpl进行处理。

  其实这时候并不觉得有什么问题,因为就算是new一个对象出来,解析完也可以回收。但是在本地单抽这段代码出来for循环然后Thread.sleep(10)执行,发现问题复现,olden区内存占用持续升高,开始觉得不对劲。debug了下fastjson的源码,发现fastjson是会将解析过的type对象进行缓存,并放到一个IdentityHashMap中,其中计算hash值是利用了 System.identityHashCode(),这个方法会直接返回对象的内存映射地址,然后以Type类型对象作为key值,那么也就是说每次new一个对象时,不管对象内容是否是一样的都会往IdentityHashMap里存放一条缓存,然后频繁逃过 young gc,进入survivor区,最后晋升变成老年代,或者是young gc回收一次后,survivor区不够放(因为这一个对象其实牵连着众多对象,涉及的内存面就较大),直接往老年代里扔。(从结果来看)

  

  至此,问题定位完毕,将数据库层的返回值用ApiResult封装后,在本地运行了下gc结果变为正常。

  第二天调整完后上压测,测试反馈接口已正常,查看jvm各区内存使用情况也已正常。通知经理可以按正常排期上线。

我一直承受着这个年纪不该承受的压力

总结:

1.jstat命令 jmap命令 ,以及jvisualvm等工具的使用要熟练。

2.对JVM的分区以及垃圾回收的流程要有一定的了解,厚积薄发,多看多学,总有用到的地方。

3.使用别人的东西前需要对这个东西有一个大概的了解,这次就是事先有review过一部分平台组的代码,对结构有大概的了解才定位起来比较快。

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值