背景
JSON(JavaScript Object Notation)是一种非常轻量级且成熟的数据交换格式,不仅人可以简单阅读编写,机器解析与生成的代价也较低,被程序开发设计广泛使用。市面上json框架层出不穷,本次我们就来亲自测试下各个框架的性能以便学习和后期工作使用。
测试思路
本次测试使用复杂数据结构,因为仅使用基本数据结构测试,发现性能偏差基本不大,不能体现出差距,而且实际使用中,各种类型基本都会使用,使用所有类型测试尽量平均实验结果。
实验对象及简介
本次主要研究主流的三个框架:
Gson(2.8.6)
Google公司出品,使用简单功能齐全版本稳定,且源码设计清晰巧妙,是学习工作的神器。
fastjson(1.2.68)
阿里巴巴公司开发产品,采用独特算法(具体多独特我也没研究清楚,等有时间研究清楚了继续完善吧)效率据说是最快的
Jackson(2.9.9)
万般介绍都不如一句-------Spring mvc默认json解析工具。
测试代码
通用接口定义:
public interface JsonInterface {
/**
* json序列化
* @return
*/
public String toJson(Object obj);
/**
* json反序列化
* @param jsonStr
* @param t
* @param <T>
* @return
*/
public <T>T parseObj(String jsonStr,Class<T> t);
}
Gson工具类实现
public class GsonUtils implements JsonInterface {
Gson gson = new Gson();
@Override
public String toJson(Object obj) {
return gson.toJson(obj);
}
@Override
public <T> T parseObj(String jsonStr, Class<T> t) {
return gson.fromJson(jsonStr, t);
}
}
fastjson工具类实现
public class FastJsonUtils implements JsonInterface {
@Override
public String toJson(Object obj) {
return JSON.toJSONString(obj);
}
@Override
public <T> T parseObj(String jsonStr, Class<T> t) {
return JSON.parseObject(jsonStr,t);
}
}
Jackson工具类实现
public class JacksonUtils implements JsonInterface {
ObjectMapper mapper = new ObjectMapper();
@Override
public String toJson(Object obj) {
try {
return mapper.writeValueAsString(obj);
} catch (JsonProcessingException e) {
e.printStackTrace();
}
return null;
}
@Override
public <T> T parseObj(String jsonStr, Class<T> t) {
try {
return mapper.readValue(jsonStr,t);
} catch (IOException e) {
e.printStackTrace();
}
return null;
}
}
module定义(尽量复杂类型):
public class T1 {
private String p1 = "西红柿";
private int p2 = 30;
private double p3 = 1.78;
private float p4 = 1.85f;
private Date p5 = new Date();
private String[] p6 = new String[]{"a","b","c"};
private T2 p7 = new T2();
private List<T2> p8 = new ArrayList<T2>(){{
add(new T2());
add(new T2());
add(new T2());
}};
private Map<String,String> p9 = new HashMap<String,String>(){
{
put("a","1");
put("b","2");
put("c","3");
put("d","4");
}
};
private Map<String,T2> p10 = new HashMap<String,T2>(){
{
put("a",new T2());
put("b",new T2());
}
};
}
public class T2 {
private String p1 = "西红柿";
private int p2 = 30;
private double p3 = 1.78;
private float p4 = 1.85f;
private Date p5 = new Date();
private String[] p6 = new String[]{"a","b","c"};
}
注:本次测试的数据都在以上module基础上进行,因为简单基本数据类型测试性能结果各个框架基本没太大区别。
测试开始
1.序列化测试
执行时间维度
Gson执行
static int[] counts = new int[]{1000,10000,100000,1000000};
public static void main(String[] args) {
JsonInterface jsonInterface = new GsonUtils();
T1 t1 = new T1();
for (int k = 0; k < counts.length; k++) {
long start = System.currentTimeMillis();
for (int i = 0; i < counts[k]; i++) {
jsonInterface.toJson(t1);
}
long end = System.currentTimeMillis();
out.println(k+"次 take:"+(end - start));
}
}
先测试一个小点,gson对象每次创建对性能的影响(当然大家一看都知道会损耗性能,但是会损耗多少呢?而且据我观察,很对人为了简单经常这样写,所以测试下这样写的严重性)即:
public class GsonUtils implements JsonInterface {
@Override
public String toJson(Object obj) {
Gson gson = new Gson();
return gson.toJson(obj);
}
}
如上表格,这种写法会导致每次平均序列化时间提高2.5 – 3.7倍
所以日常使用建议Gson对象只创建一次
如上结果,执行次数较多时候, fastjson与jackson接近,gson相对较弱,所以推测fastjson与jackson比较适合服务器端长期运行性能;
另外发现fastjson与jackson出现10000次小于1000次情况,推测可能时首次初始化的资源会比较大,所以我们继续降低执行频率对比接近首次执行情况
T1 t1 = new T1();
long start = System.currentTimeMillis();
for (int i = 0; i < 1; i++) {
jsonInterface.toJson(t1);
}
long end = System.currentTimeMillis();
out.println("次 take:" + (end - start));
按如上单独次数运行
如上对比发现,fastjson在处理低频率处理场景,初始化时间比较久,而gson与jackson相对领先
内存占用维度
JsonInterface jsonInterface = new GsonUtils();
// JsonInterface jsonInterface = new JacksonUtils();
// JsonInterface jsonInterface = new FastJsonUtils();
T1 t1 = new T1();
long start = System.currentTimeMillis();
for (int i = 0; i < 1000000; i++) {
jsonInterface.toJson(t1);
}
long end = System.currentTimeMillis();
out.println(10 + "次 take:" + (end - start));
按照如上执行分别统计内存波动图
如上图可知:
Fastjson生成json占用内存较低 jackson与gson占用基本持平
2.反序列化测试
执行时间维度
String json = FileUtils.readFileToString(new File("test/jackson.json"));
long start = System.currentTimeMillis();
for (int i = 0; i < 1; i++) {
// String json = jsonInterface.toJson(t1);
jsonInterface.parseObj(json,T1.class);
}
long end = System.currentTimeMillis();
out.println("次 take:" + (end - start));
依次执行指定循环次数结果计算
如上结果,gson处理反序列化次数少时,性能较好,执行次数变多后性能远远低于另外两个的结果;
内存占用维度
String json = FileUtils.readFileToString(new File("test/jackson.json"));
long start = System.currentTimeMillis();
for (int i = 0; i < 100000; i++) {
// String json = jsonInterface.toJson(t1);
jsonInterface.parseObj(json,T1.class);
}
long end = System.currentTimeMillis();
out.println("次 take:" + (end - start));
按照如上执行分别统计内存波动图
如上图结果,gson反序列化对内存的占用在执行多次后遥遥领先。由此得出结论,gson不建议在后台高并发场景使用。
Fastjson占用内存略高于jackson
总结
在复杂对象并长期运行的情况下,Jackson与fastjson执行时间与内存占用基本接近,适合web后台使用,Gson则落后较多,最近fastjson频繁爆发安全漏洞,建议使用jackson替换;
Gson(235K),fastjson(655K),Jackson(318K+65K+1317K),gson包相对其他包比较精简,对象轻量,适合客户端应用使用。
ps:转载请注明出处,谢谢!