导出几十万行数据时脚本跑到一半报 JavaScript heap out of memory,日志停在读取文件之后、写结果之前,小文件样本却能跑通。日志里能对上时间点,这种反而好排。

一次性读取的接口会把整个文件读进内存,文件多大就占多大,堆上限一到就直接崩,这跟业务逻辑写得好不好没有关系。这一点先确认清楚,后面就不用反复试。

const rl = require('node:readline').createInterface({
  input: require('node:fs').createReadStream('big.log')
});
for await (const line of rl) handle(line);

「Node 大文件流式读取」确认了原因之后,改动尽量只碰那一处,顺手改的东西后面最容易出问题。先做最小复现,能稳定跑出来的问题,排查成本会低一个数量级。

别只看报错的最后一行,往上看几行,真正的起因通常在上面。

处理上按这个顺序:改用流式读取的接口,一块一块把内容读进来;配合按行读取的工具,逐行处理每一条数据记录;写出的时候走管道,让背压来控制整体的读取速度。

结果对不对很好判断,同样体量的大文件内存曲线平稳,不再触发堆溢出,耗时也在可接受范围。

作者 9823189