应采用流式序列化替代全量JSON字符串生成,如Jackson的JsonGenerator或FastJSON2的JSONWriter直接写入输出流,分批处理、精简字段、改用Protobuf等二进制格式,并调优缓冲区与JVM参数以避免OOM。

直接把整个对象转成一个超大 JSON 字符串,很容易在堆上撑爆内存,尤其当数据本身有几百万条记录或含大字段时。关键不是“要不要序列化”,而是“怎么避免一次性生成巨量字符串”。
改用流式序列化,边写边输出
不把完整 JSON 拼成一个 String,而是写入 OutputStream 或 Writer。FastJSON2、Jackson 都支持 Streaming API:
- 用 JsonGenerator(Jackson)或 JSONWriter(FastJSON2)直接向文件、响应流或 ByteArrayOutputStream 写入,跳过中间 String 对象
- 例如导出大数据:不调
JSON.toJSONString(obj),而用generator.writeFieldName("data"); generator.writeStartArray(); for (Item item : items) { generator.writeObject(item); } - 这样内存里只存当前正在处理的几个对象 + 小缓冲区,峰值内存下降 80% 以上
分批序列化 + 合并输出
适用于需最终拼成一个完整 JSON 文件但数据无法全量加载的场景:
- 将原始数据按固定大小切片(如每 1 万条一组)
- 对每组单独序列化为字符串或字节数组,立即写入文件或输出流
- 首尾补上
[和],组间加逗号(注意最后一组不加) - 避免把所有分片字符串缓存在 List
中——那是新的 OOM 点
换更省空间的序列化格式
JSON 文本冗余高,同等数据量下比二进制格式多占 2–5 倍内存:
- 考虑用 Protobuf 或 FlatBuffers 替代 JSON,它们不生成字符串,直接操作字节数组,序列化过程几乎不分配大对象
- 若必须用 JSON,可启用 FastJSON2 的
JSONWriter.Feature.WriteNulls关闭空字段,或预过滤掉无用字段再序列化 - 对日志、调试等非传输场景,用 toString() + StringBuilder 手动拼接关键字段,避开完整序列化开销
控制 JVM 底层缓冲行为
某些 JSON 库(如 FastJSON2)内部会为写入预分配大 char[] 数组,扩容失败就报 OOM —— 实际并非真没内存:
- 设置
JSONWriter.Feature.DisableBufferAutoExpand,强制使用小缓冲并频繁 flush - 或调大底层数组上限:
System.setProperty("fastjson2.maxArraySize", "104857600")(100MB) - 配合 JVM 参数
-XX:+UseG1GC -XX:MaxGCPauseMillis=200减少大对象引发的 GC 停顿










