快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):

java 复制代码
// 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)测试案例:

java 复制代码
// 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 用来展示对象格式。

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

三、Jackson、Gson、fastjson 谁更好

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

Jackson Gson fastjson
性能 24K osp/s 205K ops/s 5.9M ops/s
生态 >240K Depends >74K Depends >1.5K Depends
安全性 87 CVE(漏洞) 4 CVE 3 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 字符串。序列化不再需要反射,也不用每次都扫描对象内容,速度自然快了。

    typescript 复制代码
    // 我自己写了个 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 的开发者是专注且创新的,这种精神值得学习!

五、参考资料

相关推荐
是小崔啊14 分钟前
开源轮子 - EasyExcel01(核心api)
java·开发语言·开源·excel·阿里巴巴
黄公子学安全23 分钟前
Java的基础概念(一)
java·开发语言·python
liwulin050624 分钟前
【JAVA】Tesseract-OCR截图屏幕指定区域识别0.4.2
java·开发语言·ocr
jackiendsc28 分钟前
Java的垃圾回收机制介绍、工作原理、算法及分析调优
java·开发语言·算法
Yuan_o_29 分钟前
Linux 基本使用和程序部署
java·linux·运维·服务器·数据库·后端
Oneforlove_twoforjob33 分钟前
【Java基础面试题027】Java的StringBuilder是怎么实现的?
java·开发语言
程序员一诺1 小时前
【Python使用】嘿马python高级进阶全体系教程第10篇:静态Web服务器-返回固定页面数据,1. 开发自己的静态Web服务器【附代码文档】
后端·python
数据小小爬虫1 小时前
利用Java爬虫获取苏宁易购商品详情
java·开发语言·爬虫
小汤猿人类1 小时前
nacos-服务发现注册
java·开发语言·服务发现
码农爱java1 小时前
设计模式--抽象工厂模式【创建型模式】
java·设计模式·面试·抽象工厂模式·原理·23种设计模式·java 设计模式