bigywater.tech
常见报错 · 32

Node.js FATAL ERROR: JavaScript heap out of memory:默认上限 4192 MB 怎么来,Buffer 为什么不触发,44 MB 的 JSON.parse 要占 92 MB

“FATAL ERROR: … JavaScript heap out of memory” 最常见的建议是 --max-old-space-size=4096。这篇在本机把上限调得很小来复现它,看默认上限怎么来、调大上限实际改变了什么、Buffer 为什么不算在内,以及一次 JSON.parse 大文件会占掉多少堆。

4192 MB
这台 16 GiB 内存的机器上 Node 26 的默认 heap_size_limit(设置值 + 96 MB)
92 MB
44 MB 的 JSON 文件 JSON.parse 之后的 heapUsed;上限 64 MB 时直接堆溢出
3 MB
分配 300 MB 的 Buffer 后的 heapUsed(Buffer 数据在堆外,不触发这个错误)

上限是多少

实测 · 本机执行输出
  本机物理内存 16 GiB
  默认:heap_size_limit = 4192 MB
  --max-old-space-size=64:heap_size_limit = 160 MB
  --max-old-space-size=256:heap_size_limit = 352 MB
  --max-old-space-size=1024:heap_size_limit = 1120 MB
  --max-old-space-size=4096:heap_size_limit = 4192 MB
  --max-old-space-size=16384:heap_size_limit = 16480 MB

由物理内存推出;--max-old-space-size 的设置值再加 96 MB 就是报告的 heap_size_limit。

报错怎么读

实测 · 本机执行输出
  node --max-old-space-size=64 leak.js(退出码 -6):
      已放入 100000 个对象,堆已用 18 MB
      已放入 200000 个对象,堆已用 30 MB
      已放入 300000 个对象,堆已用 46 MB
      已放入 400000 个对象,堆已用 63 MB
      已放入 500000 个对象,堆已用 62 MB
      <--- Last few GCs --->
      [pid:0x…]      179 ms: Mark-Compact 62.9 (65.8) -> 62.9 (65.6) MB, pooled: 1.0 MB, 24.76 / 0.00 ms (average mu = 0.056, current mu = 0.000) allocation failure; GC in old 
      FATAL ERROR: Ineffective mark-compacts near heap limit Allocation failed - JavaScript heap out of memory
      ----- Native stack trace -----

Last few GCs 里回收前后几乎没变说明回收不掉;最后一行是 Ineffective mark-compacts near heap limit。

调大有用吗

实测 · 本机执行输出
  --max-old-space-size=32  : 撞上之前最后一次打印是 200000 个对象(退出码 -6)
  --max-old-space-size=64  : 撞上之前最后一次打印是 500000 个对象(退出码 -6)
  --max-old-space-size=128 : 撞上之前最后一次打印是 1000000 个对象(退出码 -6)
  --max-old-space-size=256 : 撞上之前最后一次打印是 2100000 个对象(退出码 -6)
  --max-old-space-size=512 : 撞上之前最后一次打印是 4400000 个对象(退出码 -6)

能放的对象数大约随上限成正比增长,只是推迟,泄漏还在。

哪些不算在内

实测 · 本机执行输出
  Buffer(退出码 0):分配了 300 MB 的 Buffer:heapUsed = 3 MB,arrayBuffers = 300 MB,rss = 313 MB
  普通数组(退出码 -6):FATAL ERROR: Ineffective mark-compacts near heap limit Allocation failed - JavaScript heap out of memory

Buffer 和 TypedArray 的数据在堆外。

大 JSON

实测 · 本机执行输出
  big.json 大小 44 MB,400000 条记录
  --max-old-space-size=64  (退出码 -6):FATAL ERROR: Ineffective mark-compacts near heap limit Allocation failed - JavaScript heap out of memory
  --max-old-space-size=128 (退出码 0):读文件 36 ms,JSON.parse 228 ms,400000 条,heapUsed = 92 MB
  --max-old-space-size=256 (退出码 0):读文件 13 ms,JSON.parse 217 ms,400000 条,heapUsed = 92 MB
  --max-old-space-size=512 (退出码 0):读文件 13 ms,JSON.parse 224 ms,400000 条,heapUsed = 92 MB
  流式处理,--max-old-space-size=64(退出码 0):流式扫一遍(只数记录之间的分隔 },{ ,不解析成对象)共 399999 个分隔(记录数减 1),34 ms,heapUsed = 16 MB

JSON.parse 之后堆里的占用约是文件大小的两倍;只需要扫描时用流式处理。

分步演示

堆内存
本步的对象

    本文用到的工具与边界

    • 本机 macOS 27 arm64;报错文本都是真实复现时原样捕获的(命令行工具统一用 LC_ALL=C 取英文原文,路径换成 );所有服务都是本机上自己起的、只监听 127.0.0.1,不访问外网;计时用 time.perf_counter,数字每次运行会有小幅抖动。本篇用 Node v26.12.0,本机物理内存 16 GiB;会撞上限的例子都把 --max-old-space-size 设得很小(32 到 512 MB)以便几秒内结束;“泄漏”是脚本里不断往数组里放对象,不是真实应用的泄漏;实验文件在临时目录,结束后删除
    • 没有验证:在别的内存大小的机器上默认上限是多少(只测了 16 GiB 这一台);容器里的内存限制(cgroup)对默认上限的影响;--heapsnapshot-near-heap-limit 抓堆快照并分析泄漏;--max-semi-space-size 对短命对象的影响;Worker 线程的 resourceLimits;NODE_OPTIONS 在 npm scripts 里的继承
    京ICP备2026067502号-1京公网安备11010502063487号