Java性能优化:正确的解析JSON文件

数据收集服务平均1小时OOM(java.lang.OutOfMemoryError: GC overhead limit exceeded)一次,发现都是在下载处理 JSON Atom Feed时OOM。怀疑是处理feed内存峰值消耗过大导致频繁Full GC。如下图: wu

分析过程

服务每15分钟会从Feed Server下载36个数据文件,包括12个17M,12个18M和12个100多M的文件。数据格式为JSON。由于服务是一次性加载整个JSON文件,然后转换成java对象。这个地方内存消耗可能会比较大,通过下面一组测试可以发现一些情况:

测试准备:

  • 1个16M的JSON数据文件和1个100M的JSON数据文件。
  • jackson2.3.4.Final (JSON 解析库)
  • jdk1.6.0u30

测试方法:

  • 通过Document Model API 来解析JSON文件,统计处理时间及新增内存大小
  • 通过streaming API来解析JSON文件,统计处理时间及新增内存大小

测试结果:

  • Document Model no
  • Streaming API no
  • Mem Usage Chart for Document Model (17M JSON file) - 39 Minor GC take 3.024s, 62 Full GC take 5.244s 在此输入图片描述
  • Mem Usage Chart for Streaming API(17M JSON file) - 394 Minor GC take 78ms, 30 Full GC take 557ms 在此输入图片描述

结论:

  • 下载是由5个线程并发下载,假设文件都是100M左右,那么在同一时刻的内存峰值有可能达到330Mx5,大概1.5G。基本上已经占掉了分配给整个进程的1/2。
  • 每次OOM都发生在14分-20分左右,这个时候正是数据收集服务处理数据的时候,单个进程需要处理的设备数量是18万个,如果这个时候再开始下载feed,就一定会出现OOM。

修复和改进

仔细审查feed下载和解析的流程,发现使用的是一次加载整个文件的方式,根据前面表格的数据可以得知这种方式会长期占据内存,而且源文件中有一半的字段是后期不需要的。所以决定采用新方案如下:

  • 减少并发下载feed的线程,由于前的5个改成2个。因为feed的下载和预处理并不是瓶颈,没必要在这开太多线程处理feed而导致处理是内存急剧上升。
  • 采取streaming的方式处理JSON,预先把后面不需要的数据丢弃然后保存剩余数据至缓存共后期数据处理使用。

更改后的内存占用如下图: 在此输入图片描述

对比改进之前的内存分析图(文章首部第一副图),可以看到改进后的总占用量有所下降,而且内存可以快速回收。

转载于:https://my.oschina.net/foxty/blog/383206

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值