请不要在JDK7及以上用Json-lib了
【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);
}
请不要在JDK7及以上用Json-lib了的更多相关文章
- Atitit.json类库的设计与实现 ati json lib
Atitit.json类库的设计与实现 ati json lib 1. 目前jsonlib库可能有问题,可能版本冲突,抛出ex1 2. 解决之道:1 2.1. 自定义json解析库,使用多个复合的js ...
- Json lib集成stucts2的使用方法 抛出 NestableRuntimeException异常的解决办法
首先贴出struts 2.3.16需要导入的包 因为使用的是2.3 版本,必须要导入这个包,否则会报java.lang.NoClassDefFoundError: org/apache/commons ...
- 使用JsonConfig控制JSON lib序列化
将对象转换成字符串,是非常常用的功能,尤其在WEB应用中,使用 JSON lib 能够便捷地完成这项工作.JSON lib能够将Java对象转成json格式的字符串,也可以将Java对象转换成xml格 ...
- JSON lib 里JsonConfig详解
一,setCycleDetectionStrategy 防止自包含 /** * 这里测试如果含有自包含的时候需要CycleDetectionStrategy */ public static void ...
- json lib 2.4及其依赖包下载
下载文件地址:https://files.cnblogs.com/files/xiandedanteng/json-lib-2.4%26dependencies_jars.rar 它包括 common ...
- C# Json传值与解析
最近接触了工作室的项目,觉得一个功能的实现有点不好,心想不能就动手改了下,做了才知道我的js是多么的渣,功能是这样的: 我要实现的功能就是当选择学院时,就放松get请请求到后台,后台返回json信息再 ...
- Newtonsoft.Json中的时间格式详解.
Newtonsoft.json是一款不错的序列化反序列化第三方组件,具体如何使用属于基础知识,此处不再讲解.看以下代码: public class OutgameEntity { public str ...
- Android 手机卫士--解析json与消息机制发送不同类型消息
本文地址:http://www.cnblogs.com/wuyudong/p/5900800.html,转载请注明源地址. 1.解析json数据 解析json的代码很简单 JSONObject jso ...
- iOS开发之JSON格式数据的生成与解析
本文将从四个方面对IOS开发中JSON格式数据的生成与解析进行讲解: 一.JSON是什么? 二.我们为什么要用JSON格式的数据? 三.如何生成JSON格式的数据? 四.如何解析JSON格式的数据? ...
随机推荐
- 2019年春季学期第三周作业 ----PTA作业
题目 判断上三角矩阵 上三角矩阵指主对角线以下的元素都为0的矩阵:主对角线为从矩阵的左上角至右下角的连线. 本题要求编写程序,判断一个给定的方阵是否上三角矩阵. 输入格式: 输入第一行给出一个正整数T ...
- HBuilderx中编译sass文件
安装scss/sass编译插件 工具 -> 插件安装 -> scss/sass编译插件 将sass编译成css 新建scss文件,编写完成后,(右键scss文件 -> 外部命令/插件 ...
- C# 高级编程02----手动创建C#程序
在日常工作中使用C# 开发的时候,通常使用宇宙第一神器VS进行开发.为了了解编译过程,这里采用文本编辑器的方式编写一个C#程序 一.创建一个C#程序 1.使用记事本工具创建一个名为First.cs的文 ...
- VS Code 1.28版本设置中文界面的方法
最近将vscode升级到1.28版本,发现升级后默认界面变成英文了,而且在按照网上的说法在locale.json设置locale: "zh-cn"也不起效,解决的解决方法很简单: ...
- WPF使用CefSharp嵌入网页
1.点击项目应用下的管理NuGet程序包 2.在浏览中输入cefsharp-->查找 CefSharp.Wpf-->点击安装,等待安装完成 3.如果遇到一下问题将解决方案和项目都改成64位 ...
- [原创]X-HDL 4.2安装与使用
由于涉及到VHDL工程,但实际工作中,用Verilog更多些,因此安装X-HDL进行转换,安装步骤与使用如下: X-HDL进行破解,破解如下: 安装完毕后,打开一个带转换的文件,进行如下操作: 链接: ...
- RAID磁盘阵列及CentOS7系统启动流程
磁盘阵列(Redundant Arrays of Independent Disks,RAID),有“独立磁盘构成的具有冗余能力的阵列”之意,,数据读取无影响.将数据切割成许多区段,分别存放在各个硬盘 ...
- 为什么MySQL数据库要用B+树存储索引?
小史:树的话,无非就是前中后序遍历.二叉树.二叉搜索树.平衡二叉树,更高级一点的有红黑树.B 树.B+ 树,还有之前你教我的字典树. 红黑树 一听到红黑树,小史头都大了,开始抱怨了起来. 小史:红黑树 ...
- Asp.net core 启动流程
- c/c++再学习:C++中public、protect、private的访问权限控制
C++中public.protect.private的访问权限控制 访问权限 一个类的public成员变量.成员函数,可以通过类的成员函数.类的实例变量进行访问 一个类的protected成员变量.成 ...