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

Node.js如何逐对象处理大型JSON文件以避免堆内存上限报错

问题根因
  • 解析路径配置错误:当前使用的JSONStream.parse('offers.*')会匹配到offers下的完整offer数组,需等所有数组成员全部解析完成后才会一次性抛出,3GB大小的文件对应的数组完全加载后必然超出堆内存限制。
  • 多文件并行读取:for循环会同时启动所有压缩文件的读取解析流,多个大文件同时处理会进一步推高内存占用。
修复方案
  1. 调整JSONStream匹配路径为offers.offer.*,每解析完成一个offer数组内的对象就单独抛出,无需等待整个数组加载。
  2. 改为串行处理文件,处理完成一个文件后再读取下一个,避免同时占用过多内存。
  3. 优化流处理逻辑,正确响应背压,避免数据在内存中堆积。
修改后代码
const { parentPort } = require('worker_threads')
const zlib = require('zlib')
const fs = require('fs')
const JSONStream = require('JSONStream')
const es = require('event-stream')

// 封装单个文件的处理逻辑,返回Promise方便串行控制
async function processGzFile(gzFile) {
  return new Promise((resolve, reject) => {
    const gunzip = zlib.createGunzip()
    // 修改匹配路径为每个offer数组元素
    const parser = JSONStream.parse('offers.offer.*')
    const readStream = fs.createReadStream(gzFile)

    readStream
      .pipe(gunzip)
      .pipe(parser)
      // 现在每次回调拿到的是单个offer对象,不是数组
      .pipe(es.map((rawProduct, callback) => {
        const processedProduct = getProcessedProduct(rawProduct)
        parentPort.postMessage({ processedProduct })
        callback()
      }))
      .on('error', (e) => {
        console.trace(`Error while reading file ${gzFile}`, e)
        reject(e)
      })
      .on('end', () => {
        resolve()
      })
  })
}

// 串行处理所有文件
async function processAllFiles(zippedFiles) {
  for (const gzFile of zippedFiles) {
    await processGzFile(gzFile)
  }
  // 所有文件处理完成后发送完成信号
  parentPort.postMessage({ completed: true })
}

// 启动处理
processAllFiles(zippedFiles)
可选优化

如果服务器内存充足,可在启动Node进程时添加参数扩大堆内存上限,示例如下(数值为MB,可根据实际情况调整):
node --max-old-space-size=8192 your-worker-file.js

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.26 13:24:01