Node.js堆内存不足

544

今天我运行了我的文件系统索引脚本来刷新RAID文件索引,4个小时后它崩溃并显示以下错误:

[md5:]  241613/241627 97.5%  
[md5:]  241614/241627 97.5%  
[md5:]  241625/241627 98.1%
Creating missing list... (79570 files missing)
Creating new files list... (241627 new files)

<--- Last few GCs --->

11629672 ms: Mark-sweep 1174.6 (1426.5) -> 1172.4 (1418.3) MB, 659.9 / 0 ms [allocation failure] [GC in old space requested].
11630371 ms: Mark-sweep 1172.4 (1418.3) -> 1172.4 (1411.3) MB, 698.9 / 0 ms [allocation failure] [GC in old space requested].
11631105 ms: Mark-sweep 1172.4 (1411.3) -> 1172.4 (1389.3) MB, 733.5 / 0 ms [last resort gc].
11631778 ms: Mark-sweep 1172.4 (1389.3) -> 1172.4 (1368.3) MB, 673.6 / 0 ms [last resort gc].


<--- JS stacktrace --->

==== JS stack trace =========================================

Security context: 0x3d1d329c9e59 <JS Object>
1: SparseJoinWithSeparatorJS(aka SparseJoinWithSeparatorJS) [native array.js:~84] [pc=0x3629ef689ad0] (this=0x3d1d32904189 <undefined>,w=0x2b690ce91071 <JS Array[241627]>,L=241627,M=0x3d1d329b4a11 <JS Function ConvertToString (SharedFunctionInfo 0x3d1d3294ef79)>,N=0x7c953bf4d49 <String[4]\: ,\n  >)
2: Join(aka Join) [native array.js:143] [pc=0x3629ef616696] (this=0x3d1d32904189 <undefin...

FATAL ERROR: CALL_AND_RETRY_LAST Allocation failed - JavaScript heap out of memory
 1: node::Abort() [/usr/bin/node]
 2: 0xe2c5fc [/usr/bin/node]
 3: v8::Utils::ReportApiFailure(char const*, char const*) [/usr/bin/node]
 4: v8::internal::V8::FatalProcessOutOfMemory(char const*, bool) [/usr/bin/node]
 5: v8::internal::Factory::NewRawTwoByteString(int, v8::internal::PretenureFlag) [/usr/bin/node]
 6: v8::internal::Runtime_SparseJoinWithSeparator(int, v8::internal::Object**, v8::internal::Isolate*) [/usr/bin/node]
 7: 0x3629ef50961b

服务器配备了16GB的RAM和24GB的SSD交换空间。我非常怀疑我的脚本是否超过了36GB的内存。至少不应该超过。

脚本创建了文件索引,存储为对象数组,并包含文件元数据(修改日期、权限等,没有大量数据)

以下是完整的脚本代码: http://pastebin.com/mjaD76c3

我以前已经遇到过这个脚本的一些奇怪的问题,例如,当处理像字符串这样大的文件时,节点会出现故障,因此我不得不将索引拆分成多个文件。有没有办法改善Node.js对大型数据集的内存管理?


6
对于Windows的命令提示符(cmd):set NODE_OPTIONS=--max-old-space-size=8192 的意思是设置Node.js进程的最大内存限制为8192 MB。 - shabarinath
有人能确认这个问题是否可能是由于 CPU 不足引起的吗?在我的情况下,我有 32GB 的 RAM,并为节点选项指定了约 11G,但只有 2 个CPU。仍然会出现 OOM。 - Rajesh Swarnkar
我在tsconfig.json的compilerOptions中添加了"memoryLimit": 4096。 这对我起了作用。 - undefined
34个回答

543

如果我没记错的话,V8 对内存使用有一个严格的标准限制,大约是1.7GB,如果您不手动增加它的话。

在我们的一个产品中,我们在部署脚本中遵循了这个解决方案:

 node --max-old-space-size=4096 yourFile.js

还将有一个新的空间命令,但正如我在这里阅读的一样:a-tour-of-v8-garbage-collection,新空间仅收集新创建的短期数据,而旧空间包含所有引用的数据结构,这在你的情况下应该是最佳选择。


同样,这个配置适用于Node.js,不受框架的影响。@Simer - Felix
10
我正在使用Angular 4进行开发,并遇到了相同的问题,你的angular应用程序中应该是什么yourFile.js文件? - Vikram
@VikramSingh,你是使用ng serve还是通过另一个Web服务器(如express)分发ng build的/dist文件夹的结果?但是,如果您的Angular项目使用的内存超过标准的1.7GB,则可能存在应用程序中的架构问题?看起来你正在使用nmp start的开发环境,也许这是解决方案 https://github.com/mgechev/angular-seed/issues/2063 - Felix
7
在你的File.js文件中,应该放置哪个文件?是Nodemon文件还是NodeJS文件? - Techdive
2
index.js文件是@Techdive中用于启动服务器的文件。 - Basit
显示剩余4条评论

246

如果你想全局增加节点的内存使用量 - 不仅是单个脚本,你可以像这样导出环境变量:


export NODE_OPTIONS=--max_old_space_size=4096

然后在运行构建时就不需要再操作文件了,例如:


npm run build

2
为了方便起见,将其添加到bash_profile或zsh配置文件中。 - Tropicalrambler
1
即使将 NODE_OPTIONS 设置为 4096 或更高,我仍然收到相同的错误。当我运行命令 npm run build 时,我看到一些进程正在运行,命令类似于 usr/bin/node --max_old_space_size=2048。可能的原因是什么? - Ayesh Weerasinghe
2
@AyeshWeerasinghe 可能是您正在使用或运行的库或脚本具有硬编码的 max_old_space_size 参数,该参数会覆盖导出的环境变量。 - Maksim Luzik
1
需要用双引号将值包裹起来,例如 export NODE_OPTIONS="--max-old-space-size=4096"。 - kaya
1
想知道是 --max_old_space_size 还是 --max-old-space-size
所有选项,包括 V8 选项,都允许使用破折号 (-) 或下划线 (_) 分隔单词。例如,--pending-deprecation 等同于 --pending_deprecation
https://nodejs.org/docs/latest-v18.x/api/cli.html#options
- undefined

132

以防在不能直接设置节点属性的环境中遇到此问题(在我的情况下是构建工具):

NODE_OPTIONS="--max-old-space-size=4096" node ...

如果您无法通过命令行传递节点选项,则可以使用环境变量来设置它们。


4
当你说“...使用环境变量设置节点选项”时,你的意思是通过设置环境变量来配置节点的选项。 - Keselme
7
环境变量是在服务器上设定的可以被所有进程读取数据的变量。打开SSH终端连接到你的服务器,然后输入:MY_VAR=hello,接着输入:echo $MY_VAR。你会看到终端输出了“hello”。你刚刚设定了一个环境变量并且读取了它。 - Rob Evans
我在Ubuntu 18.04上工作,只是将导出命令添加到我的bashrc文件中。 - Rahal Kanishka

101

以下是一些标志值,可以提供更多信息来允许在启动节点服务器时使用更多内存。

1GB - 8GB

#increase to 1gb
node --max-old-space-size=1024 index.js

#increase to 2gb
node --max-old-space-size=2048 index.js 

#increase to 3gb
node --max-old-space-size=3072 index.js

#increase to 4gb
node --max-old-space-size=4096 index.js

#increase to 5gb
node --max-old-space-size=5120 index.js

#increase to 6gb
node --max-old-space-size=6144 index.js

#increase to 7gb
node --max-old-space-size=7168 index.js

#increase to 8gb 
node --max-old-space-size=8192 index.js 


1
可以将其以2的幂不断增加吗?应该将其设置为大于系统内存吗?如果不是,那么什么是良好的系统内存与max-old-space-size比率? - Harry Moreno
6
@HarryMoreno 你实际上可以输入任何数字值,不一定是2的幂次方。但是关于比例我不确定。它只是一个最大限制,不会使用所有内存。我建议你将其设置为所需的最高值,然后根据需要进行缩小。 - Nicholas Porter
我会尝试给系统RAM减少1GB。假设这个虚拟机只用于运行此节点应用程序。 - Harry Moreno
2
@HarryMoreno 一个良好的系统内存与最大旧空间大小比率完全取决于您的计算机上运行的其他内容。您可以按二的幂增加它,或者您可以使用任何数字。您可以将其设置为大于系统内存的值,但是您将遇到交换问题。 - Gigimoi

65
我刚刚遇到了与我的EC2实例t2.micro相同的问题,它只有1GB的内存。
我通过使用this链接创建了交换文件,并设置了以下环境变量来解决这个问题。
export NODE_OPTIONS=--max_old_space_size=4096
最终问题解决了。

谢谢分享。我遇到了同样的问题,你的提示对我很有用。 - Henrique Van Klaveren
3
谢谢。我现在能够在我的 $5/mo Linode nanode 实例上通过创建一个 2GB 的交换文件并在 Dockerfile 中添加 "ENV NODE_OPTIONS=--max_old_space_size=1024" 来运行 Strapi 的 "yarn build" 命令。不确定在我的情况下是否需要进行交换步骤,但这样做也无妨。 - Anubisoft
太好了!Azure Standard_B1s 对我来说可行。 - Andre Mesquita
准确地说,对于小型机器,您可能需要使其更小而不是更大,例如导出NODE_OPTIONS = --max_old_space_size = 1024。 - Ossip

33

即使我设置了 --max-old-space-size,我仍然在这个问题上苦苦挣扎。

后来我意识到需要在karma脚本之前加上选项--max-old-space-size。

最好同时指定两种语法--max-old-space-size和--max_old_space_size,我的karma脚本如下:

node --max-old-space-size=8192 --optimize-for-size --max-executable-size=8192  --max_old_space_size=8192 --optimize_for_size --max_executable_size=8192 node_modules/karma/bin/karma start --single-run --max_new_space_size=8192   --prod --aot

参考 https://github.com/angular/angular-cli/issues/1652


9
最好同时指定 --max-old-space-size 和 --max_old_space_size 两个语法,但其实不必这样做,它们是同义词。参考 https://nodejs.org/api/cli.html#cli_options:所有选项,包括 V8 选项,都允许用破折号 (-) 或下划线 (_) 来分隔单词。 - ZachB
7
max-executable-size已被移除,如果使用会出现错误:https://github.com/nodejs/node/issues/13341 - crashbus
我不得不将其削减为 --max-old-space-size=8192 --optimize-for-size --max_old_space_size=8192 --optimize_for_size,然后它就可以工作了。 - Sergey Pleshakov
谢谢,你是绝对的救星。optimize-for-size 最终使我的构建成功了。 - Constantinos

29

我在使用VSCode调试时遇到了这个问题,所以我想说这就是你如何将参数添加到你的调试设置中。

你可以将它添加到launch.json文件中配置的runtimeArgs属性中。

请参考以下示例:

{
"version": "0.2.0",
"configurations": [{
        "type": "node",
        "request": "launch",
        "name": "Launch Program",
        "program": "${workspaceRoot}\\server.js"
    },
    {
        "type": "node",
        "request": "launch",
        "name": "Launch Training Script",
        "program": "${workspaceRoot}\\training-script.js",
        "runtimeArgs": [
            "--max-old-space-size=4096"
        ]
    }
]}

1
launch.json和package.json是相同的吗? - SoJS
不是,launch.json 是一个专门用于在 VS Code 中运行应用程序的配置文件。 - Charles Stover
VS Code 的 launch.json 文件在哪里? - Ciaran Gallagher

28

1
干杯,这对我有用。可能需要使用 sudo npm -g install increase-memory-limit --unsafe-perm 命令安装 increase-memory-limit 模块。 - Leo
4k 不够用。开发者一直将其保持在 4k 上。开发者提供了一个好的解决方案。当我浏览 npm 页面时,我没有看到有关更改限制值的信息。实际上,有一个解决方案,但它没有起作用。 - withoutOne
1
现在已经是2021年了,因为该库被标记为弃用,所以必须有更好的替代方案:https://www.npmjs.com/package/increase-memory-limit - dawsnap
1
运行完这个命令后,我输入了 npm run dev,但它停在那里。它没有显示任何进度,也没有在这一行 > webpack-dev-server --config ./webpack.dev.config.js 后给出任何错误信息。它就像是卡住了,所以项目无法运行。 - Vikas Acharya

23

我只想补充一点,在某些系统中,即使使用--max-old-space-size增加节点内存限制,仍然不足以解决出现如下操作系统错误的问题:

terminate called after throwing an instance of 'std::bad_alloc'
  what():  std::bad_alloc
Aborted (core dumped)

可能是因为您已达到每个进程的最大mmap数量限制。

您可以通过运行以下命令检查max_map_count:

sysctl vm.max_map_count

通过运行来增加它

sysctl -w vm.max_map_count=655300

通过添加这行代码,可以修复在重新启动后不会重置的问题。

vm.max_map_count=655300

/etc/sysctl.conf文件中。

更多信息请查看此处

通过使用strace运行该进程来分析错误的好方法。

strace node --max-old-space-size=128000 my_memory_consuming_process.js

strace提示有效,但请注意,如果您正在使用Node Alpine基础映像的Docker,则必须自行安装strace - Venryx
1
请注意,strace 会产生大量的输出行,这将妨碍您查看常规日志行的能力(除非您对输出进行某种过滤)。有没有办法减少这种噪音,只显示与 std::bad_alloc 错误相关的事件? - Venryx

18

最近我也遇到了同样的问题,在这个线程中找到了解决方法,但我的问题出现在React应用程序中。下面更改了节点启动命令以解决我的问题。

语法

node --max-old-space-size=<size> path-to/fileName.js

例子

node --max-old-space-size=16000 scripts/build.js

为什么max-old-space-size中的大小是16000?

基本上,它取决于线程分配的内存和您的节点设置。

如何验证并确定正确的大小?

这基本上留在我们的引擎v8中。下面的代码可以帮助您了解本地节点v8引擎的堆大小。

const v8 = require('v8');
const totalHeapSize = v8.getHeapStatistics().total_available_size;
const totalHeapSizeGb = (totalHeapSize / 1024 / 1024 / 1024).toFixed(2);
console.log('totalHeapSizeGb: ', totalHeapSizeGb);

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接