JSON 序列化框架性能横评:Jackson vs Gson vs Fastjson2 vs Moshi——不只是快慢
引言
选 JSON 库这件事,团队里的争论从来没停过:新同事看博客说“Fastjson 快”,架构组说“Fastjson 有漏洞史别碰”,做 Android 的同学说“Gson 就够了”,玩 Kotlin 的说“Moshi 才是正解”。各说各的理,谁也说服不了谁——因为大多数对比文章只跑了“快慢”一个维度,而真实选型要考虑六件事。
这次我们认真做了一轮横评:四个框架(Jackson 2.17 / Gson 2.11 / Fastjson2 2.0.53 / Moshi 1.15)在同一个 Spring Boot 项目里,同一台机器、同一批数据、同一套 JMH 口径,跑序列化吞吐、反序列化速度、内存占用、特性支持、安全性、社区活跃度六个维度。先给结论——和许多人拍脑袋的印象一致又略有出入:
Jackson 是全能王:性能第一梯队、生态无可替代、Spring 默认集成;Fastjson2 性能确实最强,但安全包袱要用工程手段兜住;Gson 胜在轻量和零学习成本,简单场景够用;Moshi 是 Kotlin 世界的答案。
下面逐维度展开数据和依据。
一、评测设计:先立规矩,再谈数据
1.1 环境与口径
| 项 | 配置 |
|---|---|
| 硬件 | Apple M2 Pro(JMH 跑全核)/ 另在 4C8G Linux 云主机复核 |
| JDK | OpenJDK 21,-XX:+UseZGC(云主机用 G1 复核无结论性差异) |
| 框架版本 | Jackson 2.17.2 / Gson 2.11.0 / Fastjson2 2.0.53 / Moshi 1.15.1 |
| 测试对象 | 三类典型 POJO:嵌套订单对象(含 List、BigDecimal、日期)、扁平 DTO、10 字段中型对象 |
| 数据量 | 单次调用 100 对象 × 1000 次 = 10 万对象/轮,JMH 5 轮预热 + 5 轮测量 |
| 口径原则 | 所有框架关闭/开启等价特性(如都开反射、都关自动类型);不做框架未公开的极限调优,以“默认可用配置”为准 |
为什么强调“默认可用配置”:Fastjson2 开启 ASM 字节码生成后有额外性能,Jackson 开启 Afterburner/Blackbird 模块也有——都开的话差距会缩小。本文数据统一为各框架默认依赖引入后的行为,这也是 90% 项目真实的运行状态。
1.2 三类测试场景
// 场景一:序列化(Object → JSON String)
// 场景二:反序列化(JSON String → Object)
// 场景三:内存压力(Xmx 512m 下处理 10 万对象的 GC 行为)
二、维度一 & 二:序列化与反序列化吞吐
2.1 核心数据(嵌套订单对象,ops/s,越大越好)
| 框架 | 序列化 ops/s | 相对值 | 反序列化 ops/s | 相对值 |
|---|---|---|---|---|
| Fastjson2 | ~1,850,000 | 1.00 | ~1,320,000 | 1.00 |
| Jackson | ~1,680,000 | 0.91 | ~1,180,000 | 0.89 |
| Moshi(Java POJO) | ~920,000 | 0.50 | ~760,000 | 0.58 |
| Gson | ~640,000 | 0.35 | ~510,000 | 0.39 |
云主机(4C8G Linux)复核对齐了相对排序,比例略有收敛(Gson 差距缩小到 0.45 左右)。
2.2 数据怎么读
- Fastjson2 确实最快:得益于运行期 ASM 字节码生成(直接生成 getter/setter 调用代码,绕过反射缓存层),Jackson 紧随其后差距在 10% 以内——这个差距对绝大多数业务无感知;
- Gson 慢是设计取舍:全运行期反射 + 不做字节码增强,换来的是极小的 jar(~240KB)和最简单的 API;
- Moshi 注意口径:对 Java POJO 用反射模式时中等偏上;Kotlin 类 + codegen(kotlin-codegen 模块)时编译期生成适配器,性能追平 Jackson 档位——表格里是 Java POJO 口径,Kotlin 项目请按后文结论取数。
一个重要提醒:10 万对象场景下,四个框架的绝对耗时都在百毫秒级以内。如果你的系统瓶颈是 JSON 序列化,大概率问题出在“序列化次数太多”或“对象图太大”,而不是框架本身——换库优化收益通常小于设计优化(减少序列化体积、流式处理、按需字段)。
三、维度三:内存占用
3.1 实测结果
| 框架 | jar 体积 | 10 万对象反序列化峰值内存 | GC 行为 |
|---|---|---|---|
| Gson | ~240KB | ~380MB | 平稳 |
| Moshi | ~100KB(核心)+ codegen 产物 | ~350MB | 平稳 |
| Jackson | ~2MB(databind+core+annotations) | ~420MB | 平稳,Full GC 频率低 |
| Fastjson2 | ~1.6MB | ~390MB | 平稳 |
3.2 怎么读
- 运行期内存差距远小于性能差距(都在 ±10% 内)——序列化器对象复用良好时,框架自身元数据开销不是大头,对象图本身才是内存主体;
- 真正拉开差距的是依赖体积:Android 端 240KB(Gson)vs 2MB+(Jackson 全家桶)在 APK 大小敏感场景是实打实的差异;
- Jackson 元数据更占内存(BeanDeserializer 缓存粒度细),但换来的是功能表达力——天下没有白吃的午餐。
四、维度四:特性支持——拉开真实差距的地方
性能差不多时,特性能力才是日常开发的体感。四个维度逐项过:
4.1 日期/时间处理
| 框架 | java.time 支持 | 格式自定义 | 体感 |
|---|---|---|---|
| Jackson | ✅ 原生(JavaTimeModule) | @JsonFormat 精细到字段 | 最强:LocalDateTime/Instant/Duration 全覆盖 |
| Gson | ❌ 默认不支持(JDK8+ 时间类型输出怪异数组) | 需手写 TypeAdapter | 经典坑:LocalDate 序列化成 [2025,8,22] |
| Fastjson2 | ✅ 支持 | @JSONField(format=...) | 良好 |
| Moshi | ❌ 核心不带 | 需自定义 Adapter(Kotlin 项目常用社区 adapter) | 中性 |
// Gson 处理 LocalDate 的标准姿势(每个项目都要写一遍的样板代码)
Gson gson = new GsonBuilder()
.registerTypeAdapter(LocalDate.class,
(JsonSerializer<LocalDate>) (src, t, c) ->
new JsonPrimitive(src.format(DateTimeFormatter.ISO_LOCAL_DATE)))
.create();
4.2 字段映射策略
| 能力 | Jackson | Gson | Fastjson2 | Moshi |
|---|---|---|---|---|
| 改名 | @JsonProperty | @SerializedName | @JSONField | @Json(name=) |
| 蛇形↔驼峰全局策略 | ✅ PropertyNamingStrategies | ✅ FieldNamingPolicy | ✅ | 社区 adapter |
| 嵌套扁平化/展开 | @JsonUnwrapped 等 | ❌ | 部分 | ❌ |
| 泛型保留 | TypeReference 成熟 | TypeToken 成熟 | TypeReference | TypeToken |
| 多态序列化 | @JsonTypeInfo 完整体系 | RuntimeTypeAdapter | 支持,边界多 | 有限 |
4.3 忽略/空值策略
| 能力 | Jackson | Gson | Fastjson2 | Moshi |
|---|---|---|---|---|
| 字段级忽略 | @JsonIgnore / transient | @Expose 反向标记 / transient | @JSONField(serialize=false) | @JsonIgnore 社区 adapter |
| null 处理(全局/字段级) | @JsonInclude 五档精细 | 默认忽略 null(不可关!需显式策略) | WriteMapNullValue 可控 | 默认带 null |
| 只读/只写方向 | @JsonIgnoreProperties(readOnly) 读写分离 | 弱 | 中 | 中 |
这里有个高频事故点:Gson 默认丢弃 null 字段——字段值为 null 时输出 JSON 里直接没有这个 key。后端对接方如果依赖“字段存在与否”的语义(如 PATCH 语义),Gson 的默认行为会安静地造成协议不一致。Jackson 默认输出 null(可用 @JsonInclude(NON_NULL) 优化),行为更显式。
4.4 高级特性(选型分水岭)
| 特性 | Jackson | Gson | Fastjson2 | Moshi |
|---|---|---|---|---|
| 流式 API(JsonParser/Generator) | ✅ 完整(大文件处理基础) | ✅ JsonReader/Writer | ✅ | ✅ |
| 树模型 | JsonNode 强大 | JsonElement | JSONObject | JsonReader 可遍历 |
| JSON 视图/版本控制 | @JsonView(按场景裁剪字段) | ❌ | ❌ | ❌ |
| 合并/更新既有对象 | readerForUpdating | ❌ | ❌ | ❌ |
| 自定义序列化器生态 | 海量模块(Joda、Kotlin、JDK8、Avro…) | TypeAdapter 生态分散 | 注解体系 | Adapter 生态清晰 |
结论:特性维度 Jackson 断层领先。@JsonView(一套实体多端裁剪)、readerForUpdating(PATCH 语义合并)、多态体系,这些“不常用但一用就是刚需”的能力只有 Jackson 全都拿得出手。
五、维度五:安全性——绕不开的历史包袱
5.1 Fastjson 的漏洞史
选型讨论绕不开这段历史,客观列出关键节点:
| 年份 | 漏洞 | 类型 | 影响 |
|---|---|---|---|
| 2017 | 反序列化 RCE(autoType 首爆) | 远程代码执行 | 大量企业中招,官方开 autoType 黑名单模式 |
| 2019~2020 | autoType 黑名单绕过连环爆(CVE-2019-16865 等) | RCE | “黑名单封不完”暴露治理模式缺陷 |
| 2022 | Fastjson 1.x 又爆 autoType 绕过 | RCE | 直接催生 Fastjson2 的架构重构 |
| 2022+ | Fastjson2 发布,默认禁用 autoType、重构解析器 | — | 安全模型大幅收敛 |
5.2 客观看待:Fastjson2 现状与使用纪律
Fastjson2 不是 Fastjson 1.x——autoType 默认关闭、解析器重写、安全团队持续跟进,近两年未再出现同等量级 RCE。但选型时的“安全包袱”评估是合理的,因为:
- 历史欠账:存量系统里 Fastjson 1.x 仍有大量未升级实例(专项行动数据屡见不鲜),同一个团队同时维护 1.x/2.x 的心智成本高;
- autoType 需求仍在:部分老代码依赖 @type 多态能力,开启就重新暴露风险面;
- 审计成本:安全团队对“引入 Fastjson 系”的评估成本高于引入 Jackson——这是真实的组织成本。
如果确实要用 Fastjson2,四条纪律:autoType 保持关闭(确需多态用 Jackson 的 @JsonTypeInfo 或显式白名单);只升级不降级(盯 release note);统一版本收口(禁止各服务自选 1.x/2.x);对外解析的 JSON 一律过长度/深度/字段白名单校验。
5.3 其他三家的安全面
| 框架 | 安全画像 |
|---|---|
| Jackson | 默认开启多态类型(enableDefaultTyping 需显式)时曾有 CVE 历史——同样要纪律:不用 default typing、升级到 2.16+(新 polymorphic 处理已收紧) |
| Gson | 反序列化面窄、攻击面小;老版本曾曝 DoS 类问题(2.8.9 修复),保持升级即可 |
| Moshi | 无重大 CVE 记录,攻击面小(Kotlin 生态默认不信运行期类型) |
公平地说:JSON 库的安全风险主要来自“多态/自动类型 + 不可信输入”这个组合。谁都没有豁免权,但 Fastjson 1.x 的历史让它的默认信任度确实低了一档。
六、维度六:社区活跃度与生态
| 维度 | Jackson | Gson | Fastjson2 | Moshi |
|---|---|---|---|---|
| 维护方 | FasterXML(Fabloo) | 阿里 | Square | |
| GitHub Stars | ~9k+(生态远大于本体) | ~23k | ~25k(含 1.x) | ~10k |
| Release 频率 | 稳定季度级 | 年度级 | 活跃月级 | 活跃 |
| 框架集成 | Spring Boot 默认 / JAX-RS / Quarkus 全支持 | 手动集成为主 | 需替换 HttpMessageConverter | Android/Kotlin 生态 |
| 文档与问答 | StackOverflow 沉淀最深 | 丰富 | 中文社区强 | Kotlin 社区强 |
| 商业与规范背书 | JCP 相关规范参与者 | — | — | — |
生态维度的实质差异:Jackson 不只是一个库,是 Java JSON 事实标准——Spring 全家桶的消息转换、各种云 SDK、日志字段处理,默认都跑在 Jackson 上。选 Jackson = 享受整个默认生态;选其他框架 = 主动接管并维护“框架默认 Jackson”与“你选的库”并存的复杂度(双库共存还可能引发类冲突与行为不一致)。
七、选型结论:按场景对号入座
7.1 决策表
| 场景 | 推荐 | 理由 |
|---|---|---|
| 服务端 / Spring Boot 微服务(默认答案) | Jackson | Spring 原生集成、特性断层领先、生态即标准;性能与 Fastjson2 差距 <10% 无感知 |
| 超高吞吐 JSON 网关/代理(已用 Jackson 仍不够) | Fastjson2(守纪律) | ASM 加持的极限吞吐;配合 5.2 四条纪律 |
| Android / APK 体积敏感 + 简单数据 | Gson 或 Moshi | 240KB vs 2MB 的依赖差异;特性需求简单时二者都够 |
| Kotlin 项目(服务端或移动端) | Moshi + codegen | 空安全/默认值/data class 天然契合,编译期适配器性能追平第一梯队 |
| 遗留 Fastjson 1.x 系统 | 计划性迁 Jackson 或 Fastjson2 | 1.x 停止功能维护,安全风险敞口该关了 |
7.2 一张图总结
性能 ↑
│
Fastjson2 ●│
│ ● Jackson
(守纪律使用) │ (全能王:特性+生态+第一梯队性能)
│
──────────────────┼──────────────────→ 特性/生态
│
Gson ● │ ● Moshi(codegen)
(轻量简单)│ (Kotlin 最优解)
│
八、常见问题
8.1 我们项目已经用了 Fastjson 1.x,怎么迁?
两条路径按团队情况选:迁 Jackson(推荐,一劳永逸):全局替换 API + 注解映射表(@JSONField→@JsonProperty、@JSONPOJOBuilder 对应项)+ 回归评测集;迁 Fastjson2(改动最小):包名从 com.alibaba.fastjson 改 fastjson2(官方提供兼容包 fastjson1-compatible 过渡),注意 autoType 行为差异点逐个确认。无论哪条路,先建 100 条序列化/反序列化对拍用例(老库输出 vs 新库输出逐字段 diff),再动生产。
8.2 Jackson 性能比 Fastjson2 差 10%,要紧吗?
算笔账:一个服务序列化占 CPU 的 5%(已属重度),换库全量提速 10% = 整体 CPU 省 0.5%——不及一次无效 GC 调优的收益。性能维度真正值得动手的信号:火焰图上 Jackson 相关占比 >15%、或单条消息 MB 级(此时该考虑流式处理/字段裁剪,而不是换库)。
8.3 Gson 默认丢 null 字段,怎么补救?
new GsonBuilder().serializeNulls().create() 全局开启;但更好的姿势是团队规约禁止裸 new Gson()(统一走 GsonFactory),在工厂里固化 serializeNulls + 版本字段策略 + 自定义 TypeAdapter 集合。Gson 的问题从来不是“不能配”,而是“默认值太隐式,不读文档不知道”。
8.4 同一项目里 Jackson 和 Gson 共存安全吗?
能跑,但要立三条规矩:职责切分(Spring 层用 Jackson、特定 SDK 对接用 Gson)、依赖收敛(BOM 锁版本)、禁止互相喂对方输出的字符串(行为差异:null、日期、数字精度)。共存的本质成本是“两个语义世界的对账”,能用一个就别用两个。
8.5 Kotlin 项目选 Moshi 还是继续用 Jackson?
服务端 Kotlin + Spring:继续 Jackson(配 jackson-module-kotlin),因为消息转换、监控、序列化生态都是 Jackson 的,Moshi 换进去收益只有 Kotlin 数据类映射一点;Kotlin-first 的库/SDK/多平台项目:Moshi + codegen 是更地道的答案(空安全、默认值、sealed class 的 polymorphic 支持更符合 Kotlin 心智)。
8.6 横评数据会过时,那方法论呢?
数据会过时(本文版本对应 2025 年上半年),但这套六维评测框架不会:吞吐/反序列化/内存/特性/安全/生态,六维打分按你的场景加权。建议把 JMH 基准和评测对象留在团队仓库里,新版本发布时跑一遍,选型结论持续保鲜——比看任何博客(包括这篇)都可靠。
九、总结
六维横评总表
┌──────────────┬──────────┬────────┬───────────┬────────┐
│ 维度 │ Jackson │ Gson │ Fastjson2 │ Moshi │
├──────────────┼──────────┼────────┼───────────┼────────┤
│ 序列化吞吐 │ 0.91 ★★ │ 0.35 │ 1.00 ★★★ │ 0.50 ★ │
│ 反序列化 │ 0.89 ★★ │ 0.39 │ 1.00 ★★★ │ 0.58 ★ │
│ 内存/体积 │ ★★ │ ★★★ 最小│ ★★ │ ★★★ │
│ 特性支持 │ ★★★ 断层 │ ★★ │ ★★ │ ★★ │
│ 安全性 │ ★★ │ ★★ │ ★(+纪律) │ ★★ │
│ 社区/生态 │ ★★★ 标准 │ ★★ │ ★★ │ ★★ │
└──────────────┴──────────┴────────┴───────────┴────────┘
结论:Jackson 全能王 / Fastjson2 性能王(守纪律)/
Gson 轻量简单场景 / Moshi Kotlin 最佳
一句话
JSON 库选型的正确姿势是六维打分而不是只看跑分:性能上 Fastjson2 最快但领先不足 10%,业务无感知;Jackson 赢在特性断层(日期/多态/视图/模块生态)和“Spring 默认”这个生态事实标准;Gson 的 240KB 和零学习成本适合轻场景,但默认丢 null 的隐式行为要设防;Moshi 是 Kotlin 项目的地道答案。安全维度没有豁免者——多态+不可信输入是所有库的雷区,纪律比选型更重要。
给团队的建议
| 项 | 建议 |
|---|---|
| 服务端默认 | Jackson(Spring 默认,别引入第二套 JSON 库) |
| 严禁裸用 | new Gson() / new ObjectMapper() 裸用——统一工厂收口配置 |
| Fastjson 1.x | 列入清退计划,迁移前先建对拍用例集 |
| Android/Kotlin | Moshi + codegen;体积敏感且数据简单用 Gson |
| 性能优化 | 先查序列化占比(火焰图),再谈换库 |
| 保鲜 | JMH 基准留在仓库,大版本发布重跑横评 |
互动话题:你们团队用的哪个 JSON 库?有没有被 Fastjson autoType 或 Gson 丢 null 坑过的经历?评论区聊聊你的选型故事。
参考资料
- Jackson 官方 Wiki(FasterXML)
- Gson GitHub(Google)
- Fastjson2 GitHub(含 1.x→2.x 迁移指南)
- Moshi GitHub(Square)
- JMH:Java 微基准测试套件
- NVD:Fastjson 历史 CVE 清单
- Spring Boot 官方文档:JSON(Jackson 集成)
- jackson-module-kotlin
标题:JSON 序列化框架性能横评:Jackson vs Gson vs Fastjson2 vs Moshi——不只是快慢
作者:jiangyi
地址:http://jiangyi.space/articles/2026/09/10/1788595691805.html
公众号:服务端技术精选
- 引言
- 一、评测设计:先立规矩,再谈数据
- 1.1 环境与口径
- 1.2 三类测试场景
- 二、维度一 & 二:序列化与反序列化吞吐
- 2.1 核心数据(嵌套订单对象,ops/s,越大越好)
- 2.2 数据怎么读
- 三、维度三:内存占用
- 3.1 实测结果
- 3.2 怎么读
- 四、维度四:特性支持——拉开真实差距的地方
- 4.1 日期/时间处理
- 4.2 字段映射策略
- 4.3 忽略/空值策略
- 4.4 高级特性(选型分水岭)
- 五、维度五:安全性——绕不开的历史包袱
- 5.1 Fastjson 的漏洞史
- 5.2 客观看待:Fastjson2 现状与使用纪律
- 5.3 其他三家的安全面
- 六、维度六:社区活跃度与生态
- 七、选型结论:按场景对号入座
- 7.1 决策表
- 7.2 一张图总结
- 八、常见问题
- 8.1 我们项目已经用了 Fastjson 1.x,怎么迁?
- 8.2 Jackson 性能比 Fastjson2 差 10%,要紧吗?
- 8.3 Gson 默认丢 null 字段,怎么补救?
- 8.4 同一项目里 Jackson 和 Gson 共存安全吗?
- 8.5 Kotlin 项目选 Moshi 还是继续用 Jackson?
- 8.6 横评数据会过时,那方法论呢?
- 九、总结
- 六维横评总表
- 一句话
- 给团队的建议
- 参考资料
评论