Skip to content

AbortController/AbortSignal memory leak #55328

Closed
@System233

Description

@System233

Bug Description

The memory of the Node process grows infinitely, ultimately resulting in an OOM error. Memory profiling revealed a memory leak related to AbortController.
Similar to #54614,but the difference is that if AbortSignal.any does not have an event listener added, AbortSignal.any will eventually be released and there will be no memory leak.

I am using fetch API with AbortController/AbortSignal in Node.js(not undici directly).
Sorry, I misremembered, I was using node:http+signal.

Reproducible By

const formatMemoryUsage = (data) =>
  `${Math.round((data / 1024 / 1024) * 100) / 100} MB`;
// let i = 0;
// const registry = new FinalizationRegistry((heldValue) => {
//   i += 1;
//   // console.debug("[registry]", heldValue);
// });
let memoryData = process.memoryUsage();
console.log("Mem before loop", formatMemoryUsage(memoryData.rss));

const run = () => {
  for (let i = 0; i < 100_000; i++) {
    const abortController = new AbortController();

    const signal = abortController.signal;

    const composedSignal = AbortSignal.any([signal]);
    composedSignal.addEventListener("abort", () => {
      // It looks like the closure reference in the callback function causes the signal to not be released?
      // console.log(signal); // Uncommenting this will aggravate the memory leak
    });

    // registry.register(signal, "signal");
  }
};
setImmediate(run);
setInterval(() => {
  if (typeof global.gc == "function") {
    global.gc(true);
  } else {
    console.warn("global.gc unavailable, need '--expose-gc' flag");
  }
  const memoryData = process.memoryUsage();
  console.log("Mem after 100K iteration", formatMemoryUsage(memoryData.rss));
  // console.log(i, "signals released");
}, 1000);
/app # node --trace-gc --expose-gc  test3.js
Mem before loop 43.78 MB
[380:0x7f3bd3df6000]       44 ms: Scavenge 3.9 (5.2) -> 3.5 (6.2) MB, pooled: 0 MB, 0.74 / 0.00 ms  (average mu = 1.000, current mu = 1.000) allocation failure;
[380:0x7f3bd3df6000]       45 ms: Scavenge 3.9 (6.2) -> 3.8 (6.7) MB, pooled: 0 MB, 0.62 / 0.00 ms  (average mu = 1.000, current mu = 1.000) allocation failure;
[380:0x7f3bd3df6000]       47 ms: Scavenge 4.5 (6.7) -> 4.3 (9.2) MB, pooled: 0 MB, 0.74 / 0.00 ms  (average mu = 1.000, current mu = 1.000) allocation failure;
[380:0x7f3bd3df6000]       50 ms: Scavenge 5.9 (9.2) -> 5.4 (9.7) MB, pooled: 0 MB, 0.99 / 0.00 ms  (average mu = 1.000, current mu = 1.000) allocation failure;
[380:0x7f3bd3df6000]       53 ms: Scavenge 6.3 (9.7) -> 6.0 (14.7) MB, pooled: 0 MB, 1.20 / 0.00 ms  (average mu = 1.000, current mu = 1.000) allocation failure;
[380:0x7f3bd3df6000]       57 ms: Scavenge 9.5 (14.8) -> 8.4 (15.6) MB, pooled: 0 MB, 1.41 / 0.00 ms  (average mu = 1.000, current mu = 1.000) allocation failure; 
[380:0x7f3bd3df6000]       65 ms: Scavenge 10.6 (16.1) -> 10.0 (26.1) MB, pooled: 0 MB, 3.05 / 0.00 ms  (average mu = 1.000, current mu = 1.000) allocation failure;
[380:0x7f3bd3df6000]       80 ms: Scavenge 16.8 (26.1) -> 15.2 (27.6) MB, pooled: 0 MB, 2.62 / 0.00 ms  (average mu = 1.000, current mu = 1.000) allocation failure; 
[380:0x7f3bd3df6000]       88 ms: Scavenge 18.9 (28.5) -> 18.3 (49.8) MB, pooled: 0 MB, 3.92 / 0.00 ms  (average mu = 1.000, current mu = 1.000) allocation failure; 
[380:0x7f3bd3df6000]      104 ms: Scavenge 33.7 (51.7) -> 31.0 (53.7) MB, pooled: 0 MB, 4.48 / 0.00 ms  (average mu = 1.000, current mu = 1.000) allocation failure; 
[380:0x7f3bd3df6000]      115 ms: Scavenge 35.8 (53.7) -> 34.8 (64.9) MB, pooled: 0 MB, 7.48 / 0.00 ms  (average mu = 1.000, current mu = 1.000) allocation failure; 
[380:0x7f3bd3df6000]      127 ms: Mark-Compact 41.7 (64.9) -> 38.2 (73.8) MB, pooled: 0 MB, 2.82 / 0.00 ms  (+ 0.4 ms in 0 steps since start of marking, biggest step 0.0 ms, walltime since start of marking 12 ms) (average mu = 0.977, current mu = 0.977) finalize incremental marking via stack guard; GC in old space requested
[380:0x7f3bd3df6000]      148 ms: Scavenge 57.7 (77.6) -> 54.6 (77.6) MB, pooled: 0 MB, 4.69 / 0.00 ms  (average mu = 0.977, current mu = 0.977) allocation failure; 
[380:0x7f3bd3df6000]      159 ms: Scavenge 57.7 (77.6) -> 57.1 (89.6) MB, pooled: 0 MB, 7.86 / 0.00 ms  (average mu = 0.977, current mu = 0.977) allocation failure;
[380:0x7f3bd3df6000]      172 ms: Scavenge 70.3 (89.6) -> 67.6 (91.6) MB, pooled: 0 MB, 3.94 / 0.00 ms  (average mu = 0.977, current mu = 0.977) allocation failure; 
[380:0x7f3bd3df6000]      182 ms: Scavenge 72.7 (91.6) -> 71.6 (102.1) MB, pooled: 0 MB, 5.92 / 0.00 ms  (average mu = 0.977, current mu = 0.977) allocation failure; 
[380:0x7f3bd3df6000]      194 ms: Scavenge 83.2 (102.1) -> 80.9 (106.3) MB, pooled: 0 MB, 4.03 / 0.00 ms  (average mu = 0.977, current mu = 0.977) allocation failure; 
[380:0x7f3bd3df6000]      204 ms: Scavenge 87.3 (106.3) -> 86.0 (115.6) MB, pooled: 0 MB, 4.54 / 0.00 ms  (average mu = 0.977, current mu = 0.977) allocation failure;
[380:0x7f3bd3df6000]      216 ms: Scavenge 96.5 (115.6) -> 94.4 (120.8) MB, pooled: 0 MB, 4.04 / 0.00 ms  (average mu = 0.977, current mu = 0.977) allocation failure; 
[380:0x7f3bd3df6000]      235 ms: Scavenge 109.2 (128.3) -> 107.7 (137.1) MB, pooled: 0 MB, 5.21 / 0.00 ms  (average mu = 0.977, current mu = 0.977) allocation failure; 
[380:0x7f3bd3df6000]      255 ms: Scavenge (interleaved) 117.6 (137.1) -> 115.6 (143.3) MB, pooled: 0 MB, 6.53 / 0.00 ms  (average mu = 0.977, current mu = 0.977) allocation failure; 
[380:0x7f3bd3df6000]      273 ms: Scavenge (interleaved) 123.4 (143.3) -> 121.8 (151.6) MB, pooled: 0 MB, 7.72 / 0.00 ms  (average mu = 0.977, current mu = 0.977) allocation failure; 
[380:0x7f3bd3df6000]      279 ms: Mark-Compact 123.1 (151.6) -> 117.2 (152.7) MB, pooled: 0 MB, 3.91 / 0.00 ms  (+ 0.7 ms in 0 steps since start of marking, biggest step 0.0 ms, walltime since start of marking 44 ms) (average mu = 0.975, current mu = 0.973) finalize incremental marking via stack guard; GC in old space requested
[380:0x7f3bd3df6000]      296 ms: Scavenge 132.9 (152.7) -> 129.8 (152.7) MB, pooled: 0 MB, 4.28 / 0.00 ms  (average mu = 0.975, current mu = 0.973) allocation failure; 
[380:0x7f3bd3df6000]      308 ms: Scavenge 132.9 (152.7) -> 132.2 (165.4) MB, pooled: 0 MB, 7.98 / 0.00 ms  (average mu = 0.975, current mu = 0.973) allocation failure; 
[380:0x7f3bd3df6000]      322 ms: Scavenge 145.4 (165.4) -> 142.8 (167.9) MB, pooled: 0 MB, 4.07 / 0.00 ms  (average mu = 0.975, current mu = 0.973) allocation failure; 
[380:0x7f3bd3df6000]      333 ms: Scavenge 147.9 (167.9) -> 146.9 (178.7) MB, pooled: 0 MB, 6.16 / 0.00 ms  (average mu = 0.975, current mu = 0.973) allocation failure; 
[380:0x7f3bd3df6000]     1047 ms: Scavenge 149.1 (178.7) -> 148.6 (182.7) MB, pooled: 0 MB, 6.11 / 0.00 ms  (average mu = 0.975, current mu = 0.973) testing; 
Mem after 100K iteration 232.23 MB
[380:0x7f3bd3df6000]     2046 ms: Scavenge 148.7 (182.7) -> 148.6 (184.7) MB, pooled: 0 MB, 3.56 / 0.00 ms  (average mu = 0.975, current mu = 0.973) testing; 
Mem after 100K iteration 234.25 MB
[380:0x7f3bd3df6000]     3043 ms: Scavenge 148.6 (184.7) -> 148.6 (184.7) MB, pooled: 0 MB, 0.95 / 0.00 ms  (average mu = 0.975, current mu = 0.973) testing; 
Mem after 100K iteration 234.24 MB
[380:0x7f3bd3df6000]     4045 ms: Scavenge 148.6 (184.7) -> 148.6 (184.7) MB, pooled: 0 MB, 0.76 / 0.00 ms  (average mu = 0.975, current mu = 0.973) testing; 
Mem after 100K iteration 234.25 MB
[380:0x7f3bd3df6000]     5047 ms: Scavenge 148.6 (184.7) -> 148.6 (184.7) MB, pooled: 0 MB, 1.83 / 0.00 ms  (average mu = 0.975, current mu = 0.973) testing; 
Mem after 100K iteration 234.31 MB
[380:0x7f3bd3df6000]     6047 ms: Scavenge 148.6 (184.7) -> 148.7 (184.7) MB, pooled: 0 MB, 1.13 / 0.00 ms  (average mu = 0.975, current mu = 0.973) testing; 
Mem after 100K iteration 234.3 MB
[380:0x7f3bd3df6000]     7047 ms: Scavenge 148.7 (184.7) -> 148.6 (184.7) MB, pooled: 0 MB, 0.78 / 0.00 ms  (average mu = 0.975, current mu = 0.973) testing; 
Mem after 100K iteration 234.29 MB
[380:0x7f3bd3df6000]     8050 ms: Scavenge 148.7 (184.7) -> 148.7 (153.7) MB, pooled: 31 MB, 1.55 / 0.00 ms  (average mu = 0.975, current mu = 0.973) testing; 
Mem after 100K iteration 234.29 MB
[380:0x7f3bd3df6000]     8463 ms: Mark-Compact (reduce) 148.9 (153.7) -> 82.7 (143.4) MB, pooled: 0 MB, 10.03 / 0.00 ms  (+ 14.2 ms in 0 steps since start of marking, biggest step 0.0 ms, walltime since start of marking 27 ms) (average mu = 0.997, current mu = 0.997) finalize incremental marking via task; GC in old space requested
[380:0x7f3bd3df6000]     9051 ms: Scavenge 82.7 (143.4) -> 82.7 (144.4) MB, pooled: 0 MB, 1.57 / 0.00 ms  (average mu = 0.997, current mu = 0.997) testing; 
Mem after 100K iteration 148.13 MB
[380:0x7f3bd3df6000]     9094 ms: Mark-Compact (reduce) 82.7 (144.4) -> 82.7 (101.4) MB, pooled: 0 MB, 9.94 / 0.00 ms  (+ 16.9 ms in 0 steps since start of marking, biggest step 0.0 ms, walltime since start of marking 30 ms) (average mu = 0.992, current mu = 0.958) finalize incremental marking via task; GC in old space requested
[380:0x7f3bd3df6000]    10051 ms: Scavenge 82.7 (101.4) -> 82.7 (101.4) MB, pooled: 1 MB, 1.02 / 0.00 ms  (average mu = 0.992, current mu = 0.958) testing; 
Mem after 100K iteration 141.08 MB
[380:0x7f3bd3df6000]    11051 ms: Scavenge 82.7 (101.4) -> 82.7 (101.4) MB, pooled: 1 MB, 0.37 / 0.00 ms  (average mu = 0.992, current mu = 0.958) testing; 
Mem after 100K iteration 141.08 MB
[380:0x7f3bd3df6000]    12052 ms: Scavenge 82.7 (101.4) -> 82.7 (101.4) MB, pooled: 1 MB, 0.42 / 0.00 ms  (average mu = 0.992, current mu = 0.958) testing; 
Mem after 100K iteration 141.09 MB
[380:0x7f3bd3df6000]    13053 ms: Scavenge 82.7 (101.4) -> 82.7 (101.4) MB, pooled: 1 MB, 0.84 / 0.00 ms  (average mu = 0.992, current mu = 0.958) testing; 
Mem after 100K iteration 141.09 MB
[380:0x7f3bd3df6000]    14054 ms: Scavenge 82.7 (101.4) -> 82.7 (101.4) MB, pooled: 1 MB, 0.42 / 0.00 ms  (average mu = 0.992, current mu = 0.958) testing; 
Mem after 100K iteration 141.09 MB
[380:0x7f3bd3df6000]    15056 ms: Scavenge 82.7 (101.4) -> 82.7 (101.4) MB, pooled: 1 MB, 0.74 / 0.00 ms  (average mu = 0.992, current mu = 0.958) testing; 
Mem after 100K iteration 141.09 MB
[380:0x7f3bd3df6000]    16057 ms: Scavenge 82.7 (101.4) -> 82.7 (101.4) MB, pooled: 1 MB, 0.76 / 0.00 ms  (average mu = 0.992, current mu = 0.958) testing; 
Mem after 100K iteration 141.09 MB
[380:0x7f3bd3df6000]    17059 ms: Scavenge 82.7 (101.4) -> 82.7 (101.4) MB, pooled: 1 MB, 0.63 / 0.00 ms  (average mu = 0.992, current mu = 0.958) testing; 
Mem after 100K iteration 141.09 MB
[380:0x7f3bd3df6000]    18060 ms: Scavenge 82.7 (101.4) -> 82.7 (101.4) MB, pooled: 1 MB, 0.59 / 0.00 ms  (average mu = 0.992, current mu = 0.958) testing; 
Mem after 100K iteration 141.09 MB
[380:0x7f3bd3df6000]    19061 ms: Scavenge 82.7 (101.4) -> 82.7 (101.4) MB, pooled: 1 MB, 0.41 / 0.00 ms  (average mu = 0.992, current mu = 0.958) testing; 
Mem after 100K iteration 141.09 MB
[380:0x7f3bd3df6000]    20062 ms: Scavenge 82.7 (101.4) -> 82.7 (101.4) MB, pooled: 1 MB, 0.64 / 0.00 ms  (average mu = 0.992, current mu = 0.958) testing; 
Mem after 100K iteration 141.09 MB
[380:0x7f3bd3df6000]    21063 ms: Scavenge 82.7 (101.4) -> 82.7 (101.4) MB, pooled: 1 MB, 0.81 / 0.00 ms  (average mu = 0.992, current mu = 0.958) testing; 
Mem after 100K iteration 141.09 MB
[380:0x7f3bd3df6000]    22063 ms: Scavenge 82.7 (101.4) -> 82.7 (101.4) MB, pooled: 1 MB, 0.43 / 0.00 ms  (average mu = 0.992, current mu = 0.958) testing; 
Mem after 100K iteration 141.09 MB
/app #

Expected Behavior

All AbortController/AbortSignal should be destroyed.

Logs & Screenshots

image
image

Environment

Node: v22.3.0
Docker Image: node:apline

Additional context

Metadata

Metadata

Assignees

No one assigned

    Labels

    confirmed-bugIssues with confirmed bugs.

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions