当我在循环中读取大型JSON文件时,NodeJS耗尽了堆空间

时间:2018-05-10 06:33:58

标签: node.js v8 heap-memory

我有大约220个JSON文件,每个大约6MB,我需要解析和处理。所以,我在循环中这样做。以下是我阅读和处理它的方式:

        let fileList = fs.readdirSync('/500gb/json_files/gnip_30_p2');
        fileList = fileList.reverse();
        let totalErrors = 0;
        let totalFiles = 0;
        for (let file of fileList) { // TOTAL 220 FILES
            // READ EACH JSON FILE OF ~6MB
            let records = require(`/500gb/json_files/gnip_30_p2/${file}`);
            let results = records.results;
            if (results) {
                for (let record of results) {
                    // .. Some Processing Work Here ..
                }
            }
        }

现在问题是,在运行约3分钟后,我收到JavaScript heap out of memory错误:

[3661:0x28af890]    50503 ms: Mark-sweep 1310.9 (1467.4) -> 1310.7 (1470.9) MB, 612.9 / 0.0 ms  allocation failure GC in old space requested
[3661:0x28af890]    51132 ms: Mark-sweep 1310.7 (1470.9) -> 1310.7 (1434.4) MB, 627.7 / 0.0 ms  last resort GC in old space requested
[3661:0x28af890]    51759 ms: Mark-sweep 1310.7 (1434.4) -> 1310.7 (1429.4) MB, 626.4 / 0.0 ms  last resort GC in old space requested

没有递归调用,只有循环,读取,然后在对快速响应的服务进行一些修改后提交读取数据。那么什么可能是NodeJS耗尽堆空间的原因?这不是读取大型JSON文件并处理它们的正确方法吗?

3 个答案:

答案 0 :(得分:2)

除了要求模块之外,我不会将require用于其他任何事情。 require执行一些缓存,因此您将每个文件保存在内存中。

改为使用fs.readFile

答案 1 :(得分:0)

如其他地方所述,您将所有内容都加载到内存中。

@ everett1992建议很好,但你应该查找原因。

使用'streams'只能将文件的'块'保存在内存中。使用流,您可以将结果传递给其他函数...

查看引用的条款,有很多好文章。

答案 2 :(得分:0)

尝试

  • 仅在处理数据之前读取文件,并在之后释放文件。 例如,将require(filepath);替换为JSON.parse(fs.ReadFileSync(filepath, 'utf8'));

  • 预先准备文件。例如。将文件剪切成较小的块

这不仅限于require

HTTP请求和fs.ReadFile()将为大文件抛出Javascript heap out of memory。 (图片,JSON等)

相关:--max-old-space-size=xxxx无法解决此问题。进程的内存和缓冲区的内存之间存在区别。 See this issue

〜 就个人而言,从来没有解决这个问题,除了在阅读之前准备文件之外,还能提供更好的解决方案。

更新:查看{J}文件的JSONStream