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

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions