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

NodeJS使用JSONStream处理大JSON时出现OOM问题求助

Node.js流式处理大JSON时出现内存溢出问题

我尝试用NodeJS的JSONStream库将94MB的JSON通过HTTP请求流式传输到本地文件,但应用出现了out-of-memory错误,哪怕已经用node --max-old-space-size=256 .\main.js设置了256MB内存上限。流式处理的核心不就是用小数据块而非加载整个JSON到内存吗?是不是我的代码哪里写错了?

源代码

const http = require('http');
const JSONStream = require('JSONStream');
const https = require('https');
const { pipeline, Transform  } = require('stream');
const fs = require('fs');

const mb100 = 'https://raw.githubusercontent.com/seductiveapps/largeJSON/master/100mb.json';

// 补充缺失的isHttps函数
function isHttps(url) {
  return url.startsWith('https://');
}

new Promise((res, rej)=> {
  const url = mb100;
  const protocol = isHttps(url) ? https : http;
  const parse = JSONStream.parse('*');
  const write = fs.createWriteStream('file.json');
  const str = new Transform({
    objectMode:true,
    transform: function (chunk, encoding, callback) {
      // some computations, just an example:
      callback(null, JSON.stringify(chunk));
    }
  })
  protocol.get(url, (networkStream) => {
    pipeline(networkStream, parse, str,  write, (err) => {
      console.log(err ?? 'finish');
    });
  })
})

问题分析

你遇到内存溢出的核心原因是多余的JSON解析与序列化步骤,以及该步骤带来的内存占用:

  • 流式处理的核心确实是逐块处理数据,但JSONStream.parse('*')会将JSON数组的单个完整元素加载到内存中(而非拆分元素本身),如果原JSON里的单个元素体积较大,就会快速占用内存。
  • 你后续又将解析出的对象重新JSON.stringify(),这个过程会再次占用内存生成字符串,相当于同一数据在内存中存在对象和字符串两种形式,进一步加剧内存消耗。
  • 另外,代码中缺失isHttps函数会导致运行报错,但这不是内存溢出的直接原因。

解决方案

根据你的实际需求,分两种情况处理:

1. 仅需下载保存JSON文件(无需修改内容)

如果只是要把远程JSON文件流式保存到本地,完全不需要JSON解析和转换步骤,直接将网络流对接文件流即可,内存占用极低:

const https = require('https');
const { pipeline } = require('stream');
const fs = require('fs');

const mb100 = 'https://raw.githubusercontent.com/seductiveapps/largeJSON/master/100mb.json';

pipeline(
  https.get(mb100),
  fs.createWriteStream('file.json'),
  (err) => {
    console.log(err ?? 'finish');
  }
);

2. 需要对JSON元素做处理

如果必须处理JSON中的每个元素,优化方向如下:

  • 确认JSON结构:确保JSONStream.parse('*')匹配的是顶层数组元素,如果原JSON不是数组,需调整解析路径(比如JSONStream.parse('data.*')针对嵌套数组)。
  • 优化处理逻辑:避免不必要的序列化,若处理后仍需输出JSON,尽量直接修改解析后的对象,减少内存中重复存储的数据。
  • 控制背压:如果处理逻辑较慢,可在Transform流中通过callback的延迟调用控制数据流入速度,避免数据堆积:
    const str = new Transform({
      objectMode:true,
      transform: function (chunk, encoding, callback) {
        // 模拟耗时处理
        setTimeout(() => {
          // 示例处理逻辑
          chunk.processed = true;
          callback(null, JSON.stringify(chunk) + '\n');
        }, 10);
      }
    })
    

内容的提问来源于stack exchange,提问作者Romas Bitinas

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.18 23:33:11