You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Json转String/Bytes生成ByteArrayInputStream时抛出OOM问题咨询

根因分析

你当前的OOM本质是全量缓存大对象导致的:代码执行过程中会在堆内生成3份和JSON体积等大的对象副本:

  • StringBuilder中存储的格式化后JSON字符序列
  • jsonString.toString()生成的完整String对象
  • getBytes()生成的完整byte数组
    再加上ByteArrayInputStream本身会持有全量byte数组的引用,只要JSON体积接近堆内存上限,就会在数组拷贝阶段触发OOM。只要你还在走「先生成完整JSON字符串,再转成流写入」的逻辑,不管怎么调整读byte[]的方式,都绕不开全量对象的内存开销。
最优方案:流式序列化直接写入输出流

不要先生成完整的格式化JSON字符串,直接让JSON序列化器对接你的目标输出流tmpBufferedOutputStream,全程内存仅持有KB级别的序列化缓冲区,内存占用和JSON总大小完全无关,从根源上避免大对象OOM。
你代码里用的PrettyParams是json4s库的配置,该库原生支持流式写入,改造后的代码如下:

import org.json4s._
import java.io.OutputStreamWriter
import java.nio.charset.StandardCharsets

val writer = new OutputStreamWriter(tmpBufferedOutputStream, StandardCharsets.UTF_8)
try {
  val formatConfig = PrettyParams.nospace.copy(preserveOrder = true)
  // 直接将JSON对象渲染后逐块写入输出流,不生成全量中间字符串
  JsonMethods.render(json, formatConfig).writeTo(writer)
  writer.flush()
  tmpBufferedOutputStream.flush()
} catch {
  case e: Exception =>
    e.printStackTrace()
    throw e
} finally {
  writer.close()
}

这种方案下,序列化器会把JSON拆成小块逐段写出,哪怕JSON体积达到上百GB,只要磁盘空间足够就能正常写入,是处理大JSON的标准方案。

过渡方案:分片写入(仅适合无法修改序列化逻辑的场景)

如果你暂时无法替换现有生成formatjson字符串的逻辑,可以放弃ByteArrayInputStream和全量转byte[]的逻辑,将字符串按固定大小分片转码后直接写入输出流,至少能减少2份全量副本的内存开销:

import java.nio.charset.StandardCharsets

val chunkSize = 8192 // 8KB分片,单块内存占用极低
val totalLength = formatjson.length
var cursor = 0
val charset = StandardCharsets.UTF_8

while (cursor < totalLength) {
  val segmentEnd = Math.min(cursor + chunkSize, totalLength)
  // 每次仅处理当前分片的字符,转码后直接写出
  val segmentBytes = formatjson.substring(cursor, segmentEnd).getBytes(charset)
  tmpBufferedOutputStream.write(segmentBytes)
  cursor = segmentEnd
}
tmpBufferedOutputStream.flush()

注意:该方案依然会在内存中持有完整的formatjson字符串,如果JSON体积大到单份字符串就能撑爆堆内存,该方案依然会OOM,仅作为临时过渡使用,优先选择流式序列化方案。

避坑说明
  • 不要继续使用ByteArrayInputStream处理大内容:该类的实现要求传入完整的byte数组,本质还是全量内存缓存,无法解决大对象OOM问题
  • 不要对大字符串直接调用getBytes():该方法会申请和字符串等大的连续内存空间,大体积下极易触发堆内存不足
  • 分片处理时不要直接按byte长度切分原始字符串:UTF-8编码下多字节字符存在跨分片的可能,按字符切分后逐段转码可以避免乱码问题

内容的提问来源于stack exchange,提问作者Sathish Kumar S

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.30 03:15:38