Skip to content

Regression bug: AbortSignal.any() causing memory leak on long lived parent signal #62363

@kevgeoleo

Description

@kevgeoleo

Version

v24.13.1, v25.8.1

Platform

Linux KContainer 5.10.0-12-amd64 #1 SMP Debian 5.10.103-1 (2022-03-07) x86_64 x86_64 x86_64 GNU/Linux

Subsystem

No response

What steps will reproduce the bug?

Hi,

I would like to report a potential regression bug in Node. It can be reproduced by running the following snippet:

const ac = new AbortController();

let i = 0;
function run() {
  // This is the operation that causes the leak: repeatedly creating
  // a combined signal from the same long-lived parent signal.
  AbortSignal.any([ac.signal]);

  if (++i % 100_000 === 0) {
    const mem = process.memoryUsage().rss / 1024 / 1024;
    const kDependantSignals = Object.getOwnPropertySymbols(ac.signal).filter(
      (s) => s.toString() === 'Symbol(kDependantSignals)'
    )[0];
    const signals = ac.signal[kDependantSignals];
    console.log(`${i} - ${mem.toFixed(2)} MiB - ${signals?.size} signals`);
  }

  setImmediate(run);
}

run();

How often does it reproduce? Is there a required condition?

No specific condition

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

This issue was previously reported in #55351 and fixed in v22.12.0 'Jod' (#55354)

root@KContainer:~/temp/55351# node -v
v22.12.0
root@KContainer:~/temp/55351# node test-any-leak.cjs
100000 - 84.80 MiB - 19191 signals
200000 - 95.71 MiB - 32634 signals
300000 - 98.24 MiB - 41438 signals
400000 - 95.88 MiB - 4510 signals
500000 - 96.83 MiB - 13195 signals
600000 - 97.34 MiB - 21910 signals
700000 - 97.34 MiB - 30580 signals
800000 - 98.64 MiB - 39250 signals
900000 - 96.63 MiB - 2309 signals
1000000 - 96.99 MiB - 11092 signals
1100000 - 97.77 MiB - 19777 signals
1200000 - 97.59 MiB - 28490 signals
1300000 - 99.08 MiB - 37238 signals
1400000 - 96.63 MiB - 329 signals
1500000 - 97.71 MiB - 9057 signals
1600000 - 98.16 MiB - 17778 signals
1700000 - 98.16 MiB - 26520 signals
1800000 - 99.60 MiB - 35267 signals
1900000 - 99.43 MiB - 43989 signals
2000000 - 97.36 MiB - 7071 signals
2100000 - 98.04 MiB - 15770 signals
2200000 - 97.96 MiB - 24486 signals
2300000 - 99.22 MiB - 33191 signals

It is evident from the output that memory remains constant without increasing linearly

What do you see instead?

In node v24.13.1 and v25.8.1 - Memory usage increases quickly linearly

root@KContainer:~/temp/55351# node test-any-leak.cjs
100000 - 161.09 MiB - 30167 signals
200000 - 219.59 MiB - 43146 signals
300000 - 295.21 MiB - 2056 signals
400000 - 300.71 MiB - 102056 signals
500000 - 379.02 MiB - 202056 signals
600000 - 415.10 MiB - 56920 signals
700000 - 423.03 MiB - 156920 signals
800000 - 474.64 MiB - 256920 signals
900000 - 570.81 MiB - 356920 signals
1000000 - 621.09 MiB - 39647 signals
1100000 - 629.51 MiB - 139647 signals
1200000 - 630.28 MiB - 239647 signals
1300000 - 654.92 MiB - 339647 signals
1400000 - 740.88 MiB - 439647 signals
1500000 - 847.48 MiB - 539647 signals
1600000 - 922.58 MiB - 639647 signals
1700000 - 974.05 MiB - 46721 signals
1800000 - 981.79 MiB - 146721 signals
1900000 - 982.41 MiB - 246721 signals
2000000 - 992.41 MiB - 346721 signals
2100000 - 992.41 MiB - 446721 signals

Eventually resulting in a FATAL error:

<--- Last few GCs --->

[13503:0x6e4b000]   203625 ms: Scavenge 3702.6 (4044.6) -> 3673.9 (4056.6) MB, pooled: 0.0 MB, 14.16 / 0.00 ms (average mu = 0.237, current mu = 0.225) task;
[13503:0x6e4b000]   209229 ms: Mark-Compact (reduce) 3673.9 (4056.6) -> 3447.2 (3854.4) MB, pooled: 0.0 MB, 5592.36 / 0.00 ms (+ 1.9 ms in 2 steps since start of marking, biggest step 1.0 ms, walltime since start of marking 5603 ms) (average mu = 0.238, c
FATAL ERROR: Ineffective mark-compacts near heap limit Allocation failed - JavaScript heap out of memory
----- Native stack trace -----

 1: 0x906a3b node::OOMErrorHandler(char const*, v8::OOMDetails const&) [node]
 2: 0xb8c2ca  [node]
 3: 0xde4b55  [node]
 4: 0xde82c9  [node]
 5: 0xdfa308  [node]
 6: 0xdf9c4f  [node]
 7: 0x178c297  [node]

Additional information

No response

Metadata

Metadata

Assignees

No one assigned

    Labels

    abortcontrollerIssues and PRs related to the AbortController API

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions