Json-lib 介绍

Json-lib 是以前 Java 常用的一个 Json 库,最后的版本是 2.4,分别提供了 JDK 1.3 和 1.5 的支持,最后更新时间是 2010年12月14日。

虽然已经很多年不维护了,但在搜索引擎上搜索 "Java Json" 等相关的关键词发现好像一直还有人在介绍和使用这个库。

项目官网是:

http://json-lib.sourceforge.net/

一句话结论

Json-lib 在通过字符串解析每一个 Json 对象时,会对当前解析位置到字符串末尾进行 substring 操作。

由于 JDK7 及以上的 substring 会完整拷贝截取后的内容,所以当遇到较大的 Json 数据并且含有较多对象时,会进行大量的字符数组复制操作,导致了大量的 CPU 和内存消耗,甚至严重的 Full GC 问题。

问题分析

某天发现线上生产服务器有不少 Full GC 问题,排查发现产生 Full GC 时某个老接口量会上涨,但这个接口除了解析 Json 外就是将解析后的数据存储到了缓存中。

遂怀疑跟接口请求参数大小有关,打日志发现确实有比一般请求大得多的 Json 数据,但也只有 1MB 左右。为了简化这个问题,编写如下的性能测试代码。

package net.mayswind;import net.sf.json.JSONObject;
import org.apache.commons.io.FileUtils;import java.io.File;public class JsonLibBenchmark {public static void main(String[] args) throws Exception {String data = FileUtils.readFileToString(new File("Z:\\data.json"));benchmark(data, 5);}private static void benchmark(String data, int count) {long startTime = System.currentTimeMillis();for (int i = 0; i < count; i++) {JSONObject root = JSONObject.fromObject(data);}long elapsedTime = System.currentTimeMillis() - startTime;System.out.println(String.format("count=%d, elapsed time=%d ms, avg cost=%f ms", count, elapsedTime, (double) elapsedTime / count));}
}

上述代码执行后平均每次解析需要 7秒左右才能完成,如下图所示。

测试用的 Json 文件,“...” 处省略了 34,018 个相同内容,整个 Json 数据中包含了 3万多个 Json 对象,实际测试的数据如下图所示。

{"data":[{"foo": 0123456789,"bar": 1234567890},{"foo": 0123456789,"bar": 1234567890},...]
}

使用 Java Mission Control 记录执行的情况,如下图所示,可以看到分配了大量 char[] 数组。

翻看相关源码,其中 JSONObject._fromJSONTokener 方法主要内容如下所示。可以看到其在代码一开始就匹配是否为 "null" 开头。

private static JSONObject _fromJSONTokener(JSONTokener tokener, JsonConfig jsonConfig) {try {if (tokener.matches("null.*")) {fireObjectStartEvent(jsonConfig);fireObjectEndEvent(jsonConfig);return new JSONObject(true);} else if (tokener.nextClean() != '{') {throw tokener.syntaxError("A JSONObject text must begin with '{'");} else {fireObjectStartEvent(jsonConfig);Collection exclusions = jsonConfig.getMergedExcludes();PropertyFilter jsonPropertyFilter = jsonConfig.getJsonPropertyFilter();JSONObject jsonObject = new JSONObject();
...

而 matches 方法更是直接用 substring 截取当前位置到末尾的字符串,然后进行正则匹配。

public boolean matches(String pattern) {String str = this.mySource.substring(this.myIndex);return RegexpUtils.getMatcher(pattern).matches(str);
}

字符串 substring 会传入字符数组、起始位置和截取长度创建一个新的 String 对象。

public String substring(int beginIndex) {if (beginIndex < 0) {throw new StringIndexOutOfBoundsException(beginIndex);}int subLen = value.length - beginIndex;if (subLen < 0) {throw new StringIndexOutOfBoundsException(subLen);}return (beginIndex == 0) ? this : new String(value, beginIndex, subLen);
}

在 JDK7 及以上,调用该构造方法时在最后一行会复制一遍截取后的数据,这也是导致整个问题的关键所在了。

public String(char value[], int offset, int count) {if (offset < 0) {throw new StringIndexOutOfBoundsException(offset);}if (count <= 0) {if (count < 0) {throw new StringIndexOutOfBoundsException(count);}if (offset <= value.length) {this.value = "".value;return;}}// Note: offset or count might be near -1>>>1.if (offset > value.length - count) {throw new StringIndexOutOfBoundsException(offset + count);}this.value = Arrays.copyOfRange(value, offset, offset+count);
}

来源:大魔王mAysWINd

www.cnblogs.com/mayswind/p/9222245.html

猜你喜欢

1、GitHub 标星 3.2w!史上最全技术人员面试手册!FackBoo发起和总结

2、如何才能成为优秀的架构师?

3、从零开始搭建创业公司后台技术栈

4、程序员一般可以从什么平台接私活?

5、37岁程序员被裁,120天没找到工作,无奈去小公司,结果懵了...

6、滴滴业务中台构建实践,首次曝光

7、不认命,从10年流水线工人,到谷歌上班的程序媛,一位湖南妹子的励志故事

8、15张图看懂瞎忙和高效的区别!

请千万不要在 JDK 7+ 中使用这个 JSON 包了!切记相关推荐

  1. golang中tcp socket粘包问题和处理

    http://www.01happy.com/golang-tcp-socket-adhere/ 在用golang开发人工客服系统的时候碰到了粘包问题,那么什么是粘包呢?例如我们和客户端约定数据交互格 ...

  2. 千万级游标_在一个千万级的数据库查寻中,如何提高查询效率

    在一个千万级的数据库查寻中,如何提高查询效率? 1)数据库设计方面: a.对查询进行优化,应尽量避免全表扫描,首先应考虑在 where 及 order by 涉及的列上建立索引. b.应尽量避免在 w ...

  3. Nashorn——在JDK 8中融合Java与JavaScript之力--转

    原文地址:http://www.infoq.com/cn/articles/nashorn 从JDK 6开始,Java就已经捆绑了JavaScript引擎,该引擎基于Mozilla的Rhino.该特性 ...

  4. JDK 9中不推荐使用Java的Observer和Observable

    在博客文章< 应用JDK 9 @Deprecated增强功能>中 ,我讨论了JDK 9中 @Deprecated批注中对forRemoval()和since()可选元素(方法)的添加 . ...

  5. JDK 9中已弃用Java的Observer和Observable

    在博客文章< 应用JDK 9 @Deprecated增强功能>中 ,我讨论了JDK 9中 @Deprecated批注中对forRemoval()和since()可选元素(方法)的添加 . ...

  6. JDK 8中的流驱动的集合功能

    这篇文章介绍了JDK 8的应用–引入了带有集合的 流 ,以更简洁地完成通常需要的与集合相关的功能. 在此过程中,将演示并简要说明使用Java Streams的几个关键方面. 请注意,尽管JDK 8 S ...

  7. JDK 8中几乎命名的方法参数

    有时在Java中命名方法参数确实很不错,这看起来可能不会出现很长时间了,但是始终还有其他一些解决方法,例如使用构建器模式来获得类似的行为,这将为一点点. 在我看来,使用JDK 8中的Lambda支持可 ...

  8. java怎么查询千万数据,从java方面,在一个千万级的数据库查寻中,如何提高查询效率?...

    从java方面,在一个千万级的数据库查寻中,如何提高查询效率? 更多相关问题 请分析下面的歌曲<沂蒙山我的娘亲亲>片段中采用了那种长音或休止处的处理方法faea48d2d30c3b221e ...

  9. Java平台,标准版Oracle JDK 9中的新功能

    Java平台,标准版 Oracle JDK 9中的新增功能 版本9 E77563-05 2017年9月 JDK 9中的新功能概述 Java Platform,Standard Edition 9是一个 ...

  10. java build failed_java - maven build failed:无法在jre或jdk issu中找到Javac编译器

    java - maven build failed:无法在jre或jdk issu中找到Javac编译器 我将JAVA_HOME设置为 C:\Program Files (x86)\Java\jdk1 ...

最新文章

  1. BCH现阶段面临的一些问题以及可能的解决方向
  2. Python大法之抛 异常
  3. php页面在线人数,也谈php网站在线人数统计
  4. WINDOWS下的squid
  5. du的原理 linux_Linux 文件系统管理
  6. jquery动画 -- 1.加载指示器
  7. LeetCode 75 颜色分类
  8. 持续集成和持续部署CI/CD简介
  9. 业务请求量膨胀的扩容技术实践
  10. Java职业规划(职业晋升路线、技术转移路线、工作经验与技术栈的匹配)——学习笔记
  11. ElasticSearch 7.7.0 核心篇
  12. python强制删除文件夹_对Python各种删除文件失败的处理方式-强制删除文件
  13. PCL implicit shape model 做目标识别分类
  14. 深度学习 回声消除 AEC
  15. vim 写入错误,转换失败 (请将 'fenc' 置空以强制执行)
  16. API集成测试问题2:Expected status code 200 but received 500. Failed asserting that false is true.
  17. [转帖]彩色硬盘 关于西数硬盘 企业盘、黑盘、蓝盘、绿盘、红盘的区别
  18. 【新手上路常见问答】关于自然语言处理(NLP)
  19. 【圣诞快乐】用 C 语言画出一棵带有装饰的简易圣诞树
  20. 记录日志的工具类LogWriter

热门文章

  1. day6面向对象--继承、多态
  2. Oracle SQL篇(四)group by 分组与分组的加强 rollup
  3. SecureCRT学习之道:SecureCRT常用快捷键设置与字体设置方法
  4. webstorm配置scss自动编译路径
  5. 多层交换综合实验(二)
  6. 浅谈 MVC3 WebMail 发送邮件
  7. 「leetcode」236. 二叉树的最近公共祖先:【递归与回溯】详解
  8. vim 命令整理(自己常用)
  9. Mac磁盘项目管理工具DiskCatalogMaker
  10. Mac中将 WEBP 图片转成 JPG、PNG 格式的 2 种方法