json工具性能测试

背景
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:转载请注明出处,谢谢!

  • 3
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值