Skip to content

Fix memory leak in dev mode caused by fast-set-immediate#89779

Merged
lubieowoce merged 1 commit into
vercel:canaryfrom
alubbe:mem-leak-set-immediate-fix-1
Feb 12, 2026
Merged

Fix memory leak in dev mode caused by fast-set-immediate#89779
lubieowoce merged 1 commit into
vercel:canaryfrom
alubbe:mem-leak-set-immediate-fix-1

Conversation

@alubbe

@alubbe alubbe commented Feb 10, 2026

Copy link
Copy Markdown
Contributor

Summary

Fixes dev-time memory retention in fast-set-immediate caused by module re-evaluation chaining patched globals.

Root Cause

In dev/HMR, fast-set-immediate.external can be re-evaluated multiple times.
On each evaluation, it captured globalThis.setImmediate, globalThis.clearImmediate, and process.nextTick as “originals”. If those were already patched, new patched closures referenced older patched closures, retaining old module graphs.

I have 2GB local heapdump from a few minutes before the local dev server crashed OOM that looks like this because of it:
Screenshot 2026-02-10 at 18 49 24

What Changed

  • Added a process-wide sentinel of base/original timer functions on globalThis:
    • Symbol.for('next.fast-set-immediate.originals')
  • originalSetImmediate, originalClearImmediate, and originalNextTick now always resolve from that base sentinel, not from currently patched globals.
  • Kept the existing patch behavior/API surface:
    • install() still runs at module load
    • DANGEROUSLY_runPendingImmediatesAfterCurrentTask, expectNoPendingImmediates, and unpatchedSetImmediate exports remain available

Tests

module re-evaluation test now verifies unpatchedSetImmediate remains bound to the same base/original function across repeated jest.resetModules() reloads, and is not rebound to the previously patched global.

@nextjs-bot

nextjs-bot commented Feb 10, 2026

Copy link
Copy Markdown
Contributor

Allow CI Workflow Run

  • approve CI run for commit: 67d26a175ceeeecb4bbd529cd2dd31baccae0133

Note: this should only be enabled once the PR is ready to go and can only be enabled by a maintainer

@nextjs-bot

nextjs-bot commented Feb 10, 2026

Copy link
Copy Markdown
Contributor

Tests Passed

@alubbe

alubbe commented Feb 11, 2026

Copy link
Copy Markdown
Contributor Author

The test that failed here on CI is green for me locally, is the test flaky or am I doing something wrong? I ran

pnpm --filter @next/polyfill-module build
pnpm --filter @next/polyfill-nomodule build
pnpm --filter @next/react-refresh-utils build
pnpm --filter @next/env build
pnpm --filter=next build

NEXT_SKIP_ISOLATE=1 NEXT_TEST_MODE=dev pnpm testonly test/e2e/app-dir/actions/app-action.test.ts -t "should handle redirects to routes that provide an invalid RSC response"

@alubbe

alubbe commented Feb 12, 2026

Copy link
Copy Markdown
Contributor Author

Gentle nudge - I don't have the rights to rerun the CI and I can't reproduce this failure locally. Could someone help me figure out if it's a flaky test or whether this PR broke something?

@lubieowoce

Copy link
Copy Markdown
Member

Looks good, thanks! I'll spin CI, hopefully this is just something transient / unrelated flakeage.

@lubieowoce lubieowoce force-pushed the mem-leak-set-immediate-fix-1 branch from 67d26a1 to a7d756c Compare February 12, 2026 18:58
@lubieowoce lubieowoce merged commit 8266e03 into vercel:canary Feb 12, 2026
149 checks passed
@github-actions github-actions Bot locked as resolved and limited conversation to collaborators Feb 27, 2026
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants