在 node.js 中使用 createWriteStream 创建大文件时 JavaScript 堆内存不足致命错误:达到堆限制分配失败

Posted

技术标签:

【中文标题】在 node.js 中使用 createWriteStream 创建大文件时 JavaScript 堆内存不足致命错误:达到堆限制分配失败【英文标题】:JavaScript heap out of memory while creating a huge file using createWriteStream in node.js FATAL ERROR: Reached heap limit Allocation failed 【发布时间】:2021-09-08 01:53:09 【问题描述】:
const fs = require('fs');
const file = fs.createWriteStream('./big.file');


for(let i=0; i<1e8; i++)
    file.write(`llorem ipsum $i`);


file.end();

上面的代码尝试使用fs.createWriteStream 在node.js 中创建一个巨大的文件,据我所知,流是数据的集合,这些数据可能无法立即使用,不必放入内存。 但是当我运行我的脚本时,我的内存占用不断增加,最终导致 javascript 堆内存不足错误。 我的问题是我是否遗漏了有关流的任何内容,以及如果流不需要适合内存,为什么会发生这种情况。

脚本运行前

脚本运行后

错误

<--- Last few GCs --->

[386723:0x6297e70]    42815 ms: Mark-sweep (reduce) 2046.9 (2081.1) -> 2046.2 (2081.6) MB, 1806.1 / 0.0 ms  (+ 94.3 ms in 13 steps since start of marking, biggest step 7.6 ms, walltime since start of marking 1911 ms) (average mu = 0.341, current mu = 0.10[386723:0x6297e70]    45153 ms: Mark-sweep (reduce) 2047.7 (2081.8) -> 2046.9 (2082.1) MB, 1919.1 / 0.0 ms  (+ 123.1 ms in 16 steps since start of marking, biggest step 11.3 ms, walltime since start of marking 2057 ms) (average mu = 0.244, current mu = 0.

<--- JS stacktrace --->

FATAL ERROR: Reached heap limit Allocation failed - JavaScript heap out of memory
 1: 0xb17ec0 node::Abort() [node]
 2: 0xa341f4 node::FatalError(char const*, char const*) [node]
 3: 0xcfe71e v8::Utils::ReportOOMFailure(v8::internal::Isolate*, char const*, bool) [node]
 4: 0xcfea97 v8::internal::V8::FatalProcessOutOfMemory(v8::internal::Isolate*, char const*, bool) [node]
 5: 0xee8d35  [node]
 6: 0xef7ab1 v8::internal::Heap::CollectGarbage(v8::internal::AllocationSpace, v8::internal::GarbageCollectionReason, v8::GCCallbackFlags) [node]
 7: 0xefad0c v8::internal::Heap::AllocateRawWithRetryOrFailSlowPath(int, v8::internal::AllocationType, v8::internal::AllocationOrigin, v8::internal::AllocationAlignment) [node]
 8: 0xec72bb v8::internal::Factory::NewFillerObject(int, bool, v8::internal::AllocationType, v8::internal::AllocationOrigin) [node]
 9: 0x123052b v8::internal::Runtime_AllocateInYoungGeneration(int, unsigned long*, v8::internal::Isolate*) [node]
10: 0x16147d9  [node]
Aborted (core dumped)

【问题讨论】:

【参考方案1】:

我相信你需要检查write()的返回值,当它是false时停止写入,并利用drain事件来指示何时重新开始写入。

目前您的循环只是无限期地写入内部缓冲区而不刷新到磁盘,这就是您的脚本导致内存错误的原因。

这样的事情应该可以工作:

const fs = require('fs');
const file = fs.createWriteStream('./big.file');

const max = 1e8;
let i = 0;

file.on('drain', function writeAsMuchAsPossible() 
  while (i < max && file.write(`llorem ipsum $i++`));
  if (i === max) 
    file.end();
  
).emit('drain')

【讨论】:

以上是关于在 node.js 中使用 createWriteStream 创建大文件时 JavaScript 堆内存不足致命错误:达到堆限制分配失败的主要内容,如果未能解决你的问题,请参考以下文章

在 node.js 中使用命名参数

在 node.js 中使用 node-fetch 重用 TCP 连接

如何在 node.js 中使用 stroph.js 服务器端

如何使用 Passport.js 在 Node.js 中重置/更改密码?

使用 Javascript/Node.js 在代码中执行 mongoimport

如何在 Cappuccino 中使用 Node.js?