Node.js 循环写入流出现内存耗尽问题求助
解决Node.js写入超大CSV时的内存耗尽问题
嘿,这个坑我踩过!你明明用了流却还是内存爆了,核心问题是没处理流的背压,而且你的同步for循环根本不给流的写入逻辑留喘息的机会,直接把所有待写入的数据都堆进了内存缓冲区。咱们来一步步解决:
核心问题分析
你的同步for循环会持续调用stream.write(),但当Node.js的内部写入缓冲区被占满时,stream.write()会返回false——这时候你应该暂停写入,等缓冲区清空(触发drain事件)再继续。但你不管不顾一直写,结果所有待写入的数据都被缓存到内存里,最后直接撑爆。
修复方案
1. 处理背压,改用异步写入逻辑
把同步循环改成异步的,每次写入后检查返回值,根据drain事件来控制写入节奏:
const fs = require('fs'); const noOfRows = 2000000000; const stream = fs.createWriteStream('myFile.csv', { flags: 'a' }); function writeNextRow(currentRow) { // 所有行写完后关闭流 if (currentRow > noOfRows) { stream.end('写入完成'); return; } // 注意CSV每行要加换行符,你原来的代码没加,所有内容会挤在一行里 const rowContent = `${currentRow}\n`; // 尝试写入,返回false说明缓冲区满了,等drain再继续 if (!stream.write(rowContent)) { stream.once('drain', () => writeNextRow(currentRow + 1)); } else { // 缓冲区还能写,用process.nextTick让事件循环处理其他任务,避免阻塞 process.nextTick(() => writeNextRow(currentRow + 1)); } } // 启动写入 writeNextRow(0);
2. 额外优化建议
- 添加换行符:你原来的代码没有换行,生成的文件不是标准CSV(所有内容在一行),加上
\n才是正确的每行一条记录。 - 避免阻塞事件循环:用
process.nextTick或者setImmediate代替同步递归,让Node.js有机会处理其他I/O任务,防止程序假死。 - 可选:用成熟的CSV库:如果不想自己处理背压逻辑,可以用
fast-csv或csv-writer这类库,它们已经封装了高效的流写入逻辑,自动处理背压。
这样修改后,内存只会保留当前写入缓冲区的少量数据,不会再出现内存耗尽的问题。
内容的提问来源于stack exchange,提问作者R0b0tn1k
相关产品推荐
相关产品推荐

