快30倍!JSON序列化是Jackson?是Gson?还是谁?

一、先说结论

这次测试了三个 JSON 序列化的例子,综合来看,最快的都是 fastjson,遥遥领先第二名 Gson 30 倍

性能测试的运行环境:

CPU:Intel i5-12490f

JDK:Azul Zulu JDK 17.0.7

JMH:1.37

Gson:2.10.1

fastjson:2.0.43

Jackson:2.16.0

为了方便大家复测,我选了一个结构清晰的例子贴在这里:

被测对象(Staff):

// import 省略
public class Staff {
    private String name = "LIZI";
    private String id = "007";
    private Department department = new Department();
    private BigDecimal salary = new BigDecimal("123.456");

    public static class Department {
        private Integer id = 2;
        private Integer name = 3;
        private Integer staffCount = 4;
    }
    // Getter、Setter 省略
}

JMH(Java Microbenchmark Harness)测试案例:

// import 省略
public class SerializeBench {

    // 下面的 JSONRunnerHolder 用来初始化 ObjectMapper 和 Gson 对象
    @Fork(value = 1, warmups = 1)
    @Benchmark
    @BenchmarkMode(Mode.Throughput)
    public Object bench_jackson(JSONRunnerHolder runnerHolder) throws JsonProcessingException {
        return runnerHolder.OM.writeValueAsString(new Staff());
    }

    @Fork(value = 1, warmups = 1)
    @Benchmark
    @BenchmarkMode(Mode.Throughput)
    public Object bench_gson(JSONRunnerHolder runnerHolder) {
        return runnerHolder.GSON.toJson(new Staff());
    }

    @Fork(value = 1, warmups = 1)
    @Benchmark
    @BenchmarkMode(Mode.Throughput)
    public Object bench_fastjson() {
        return JSON.toJSONString(new Staff());
    }

}

经过五轮测试迭代,有了这样的数据:

先解释下吞吐量:

吞吐量(Throughput) = 完成的操作数量(Operations)/ 消耗的时间(Time)

吞吐量就是每秒能完成的序列化操作数,吞吐量越大,性能越好。

在 JMH 结果中,fastjson 平均每秒能完成 593 万次序列化操作,是第二名 Gson 的 30 倍,是第三名 Jackson 的 300 倍!理性得看,性能不会有这么大的差距,但我们还是可以得出一个相对的结论:fastjson 是最快的 Java JSON 序列化器!

咋会这么快?!

二、(反)序列化与JSON

(反)序列化在前后端“沟通”及后端之间的协作中扮演着关键角色。在内存中,结构化的不连续数据需要转化为连续的字节流,才能传输到 I/O 设备(如网络、硬盘)。

提问:不转化为连续数据会咋样?

回答:如果直接把对象所在的一整块数据“打包”发送出去,这样的“块”是乱的!接收方将接收到一个混乱的“块”,其中可能包含其他对象的数据,数据的内容也不紧凑。

通常根据生成数据的格式,(反)序列化分为两类方法:二进制文本。 二进制生成的数据基本没有可读性,但是生成的内容小,生成速度快,常用的技术有 ProtoBuf、Avro。

JSON(JavaScript Object Notation)则是一种“文本方法”,可读性非常好,它最早由 JavaScript 用来展示对象格式。

// 这是一个例子,name 字段是文本,age 是数字,serializer 是数组,这些是不是一样就看出来啦
{
    "name": "LiZi",
    "age": 18,
    "serializer": ["fastjson", "jackson", "gson"]
}

三、Jackson、Gson、fastjson 谁更好

其实很难说某一类技术更好,我们要基于实际需求和场景反复权衡。我根据下面四个维度对他们做了对比,以帮助大家按需选用。

JacksonGsonfastjson
性能24K osp/s205K ops/s5.9M ops/s
生态>240K Depends>74K Depends>1.5K Depends
安全性87 CVE(漏洞)4 CVE3 CVE
简便性依赖包多,有模板操作有模板操作工具类,无模板

fastjson 性能好,漏洞少(只有 3 个 CVE),使用起来更方便:不用创建 ObjectMapper/Gson 这样的模板对象,但用户却是最少的。

根据 Maven Central 统计的依赖包下载量,fastjson 在 2023 年被依赖的数量只有约 1500 个,远低于第二名 Gson 的 74000 个,即使考虑到 Maven 私有镜像,这个数字也远远落后。

在2022年以前,fastjson 在国内 Java 圈的使用量较为可观。然而,自从 CVE-2022-25845 漏洞披露了 fastjson 自动类型转换存在问题后,fastjson 的声誉受到严重打击,许多企业将其列入“黑名单”。尽管 fastjson 已经修复了问题并推出了 fastjson2,其用户量仍未恢复到之前的水平。

在选择技术时,我们要权衡很多因素。虽然 fastjson 在性能、安全性和简便性方面表现出色,但在稳定性至关重要的生产环境,Jackson 庞大的用户基数使得它成为了一个不可忽视的选择。而且,(反)序列化对接口性能的最终影响又有多大呢?

四、fastjson 咋这么快?

想必大家一直在好奇 fastjson 为什么可以这么快,fastjson 的开发者温绍锦总结到:

  1. “通过 ASM 动态 JIT 的方式针对每个 JavaBean 生成 Parser”。

    ASM 是一种运行时生成字节码的技术。字节码是 JVM 的 “指令集”。fastjson 利用 ASM 在 JVM 运行时生成了代码,这些代码就像是我们给对象写了个 toString 方法来产生 JSON 字符串。序列化不再需要反射,也不用每次都扫描对象内容,速度自然快了。

    // 我自己写了个 JSON 序列化,不让 ASM 自动生成了    
    public String toString() {
            return "{" +
                    ""name": "" + name + """ +
                    ", "age":" + age +
                    "}";
        }
    
  2. “很多编程技巧”

    fastjson 使用了 JavaLangAccess 、Unsafe这样的底层类,着重优化字符串处理,使得字符串的构建、遍历和编码都有了很大的速度提升。具体技巧可以看看:
    fastjson_string_codec_methods · alibaba/fastjson2 Wiki · GitHub

在技术上,fastjson 是优秀的。“每提升 1%,就需要 100% 的付出”,在性能上,fastjson 相比竞品却是指数级提升,需要的投入想必不少。fastjson 的开发者是专注且创新的,这种精神值得学习!

五、参考资料

  • openjdk/jmh: https://openjdk.org/projects/code-tools/jmh
  • CVE - Search CVE List
  • https://central.sonatype.com/
  • fastjson实现方式 · Issue #4102 · alibaba/fastjson
  • java - ASM在FastJson中的应用 - ksfzhaohui技术专栏 - SegmentFault 思否
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值