Node.js中保存大文件最节省内存的实现方案是什么?
错误原因
你给出的错误
20 error code ELIFECYCLE 21 error errno 137
是典型的Linux系统OOM Killer(内存溢出终止进程)触发的报错:当进程占用内存超出系统可用内存阈值时,内核会主动杀掉内存占用最高的进程释放资源,对应进程退出码就是137。
你当前使用fs.writeFileSync()写50MB JSON触发OOM的核心原因是:该方法要求你先把完整的JSON数据全量序列化为字符串后才能写入,JSON.stringify()处理大体积JSON对象时会生成大量临时变量,实际内存占用会远高于JSON本身的50MB大小。1GB内存的云服务器本身还要承载系统进程、其他服务的内存开销,剩余可用内存不足以支撑全量序列化的开销,就会触发报错,高配笔记本内存充足所以不会出现该问题。
低内存写入方案
- 流式序列化写入(最推荐)
不要一次性加载全量JSON数据到内存、全量序列化,改为边生成单条数据边写入磁盘,内存中仅保留当前正在处理的单条数据,内存占用可以降到KB级别,完全规避大内存开销。示例实现如下:
const fs = require('fs'); // 创建文件可写流 const writeStream = fs.createWriteStream('./output.json'); // 写入JSON根结构开头,如根结构是对象则写'{',是数组则写'[' writeStream.write('['); // 替换为你自己的数据源迭代逻辑,比如逐行读取数据库、逐行读取源文件,每次仅返回单条数据,不要一次性加载全量 const dataIterator = yourBusinessDataGenerator(); let isFirstItem = true; for (const item of dataIterator) { // 非第一条数据先加逗号分隔 if (!isFirstItem) writeStream.write(','); isFirstItem = false; // 仅序列化当前单条数据写入 writeStream.write(JSON.stringify(item)); } // 写入JSON根结构结尾,和开头对应 writeStream.write(']'); // 关闭可写流,结束写入 writeStream.end(() => { console.log('JSON文件写入完成'); });
- 临时调整Node堆内存上限(临时解决方案)
如果暂时无法修改数据生成逻辑,可以在启动Node脚本时增加参数调高V8堆内存上限,适配1GB内存的服务器可以设置为768MB:node --max-old-space-size=768 your-script.js
该方案为临时解决方案,当数据量继续上涨时还是会触发OOM问题。 - 清理冗余缓存
检查业务逻辑中是否存在把完整JSON对象、序列化后的全量字符串多份缓存的逻辑,删除冗余缓存变量也能降低内存开销。
内容的提问来源于stack exchange,提问作者Stewart
相关产品推荐
相关产品推荐

