nodejs / nodejs/node

v24: discarded vm contexts cause OOM; possible V8 backport

Open
#66,053 2 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

confirmed-bug v24.x v8 engine vm
Dominant language
JavaScript
Stars
122k
Forks
37.3k
Avg merge
4d 2h
Merged PRs (30d)
283

Description

Version

v24.21.0

Platform
Linux x86_64, kernel 6.8.0-139-generic
Subsystem

vm, V8

What steps will reproduce the bug?

Save as repro.mjs; run node --max-old-space-size=128 repro.mjs.

import { runInNewContext } from "node:vm";
import { setImmediate } from "node:timers/promises";

const source = `
  globalThis.payload = new Array(1_000_000).fill(0);
  ${Array.from({ length: 30 }, (_, index) => `
    function work${index}(values) {
      let result = 0;
      for (let i = 0; i < values.length; ++i) {
        result += Math.sqrt(values[i] * values[i] + ${index});
      }
      return result;
    }
  `).join("\n")}
  const values = [1, 2, 3, 4, 5];
  for (let i = 0; i < 1000; ++i) {
    ${Array.from({ length: 30 }, (_, index) => `work${index}(values);`).join("\n")}
  }
`;

for (let i = 0; i < 100; ++i) {
  runInNewContext(source + `\n// ${i}`);
  await setImmediate();
}
console.log("Completed");
How often does it reproduce? Is there a required condition?

Repeatedly on v24.15.0, v24.16.0, and v24.21.0. Completes on v22.23.2, v26.8.2, or with --no-concurrent-recompilation on v24.

What is the expected behavior? Why is that the expected behavior?

Print Completed; discarded contexts should be collectible.

What do you see instead?
FATAL ERROR: Reached heap limit Allocation failed - JavaScript heap out of memory
Additional information

This surfaced in jsdom’s WPT runner with the default ~4 GB heap; the smaller limit makes this reproduction quick. Sampled heap retainers point through V8’s IdentityMapBase to realm prototypes, keeping entire windows alive.

Could V8’s “Stop collecting array and object prototypes” change be backported to v24? Its later thread-safety follow-up might also be relevant.

I haven't verified that those commits are the key ones, but it's worth trying.

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start with repro.mjs and run it under v24 with --max-old-space-size=128, then compare v22, v26, and v24 with --no-concurrent-recompilation. Investigate the IdentityMapBase retainers and the two linked V8 commits to determine whether they address discarded vm contexts. Done means the reproduction prints "Completed" without exhausting the heap and discarded contexts can be collected.

Written by the indexing model from the issue text.

Assessment

Tech stack
javascript, node.js
Domain
backend
Issue type
Bug
Difficulty
5/5
Estimated time
Over a week
Activity status
Active
Clarity
Mostly clear
Newbie friendliness
35/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.