-
-
Notifications
You must be signed in to change notification settings - Fork 33.5k
Closed
Labels
abortcontrollerIssues and PRs related to the AbortController APIIssues and PRs related to the AbortController APIconfirmed-bugIssues with confirmed bugs.Issues with confirmed bugs.
Description
Version
v22.9.0
Platform
Microsoft Windows NT 10.0.22631.0 x64
Subsystem
No response
What steps will reproduce the bug?
const ac = new AbortController();
let i = 0;
function run() {
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?
Always
What is the expected behavior? Why is that the expected behavior?
AbortSignal.any should not case memory leaks
What do you see instead?
❯ node ..\test.js
node .\test.js
100000 - 82.29 MiB - 100000 signals
200000 - 97.98 MiB - 200000 signals
300000 - 126.98 MiB - 300000 signals
400000 - 131.91 MiB - 400000 signals
500000 - 152.07 MiB - 500000 signals
600000 - 162.52 MiB - 600000 signals
700000 - 208.69 MiB - 700000 signals
800000 - 219.15 MiB - 800000 signals
900000 - 221.80 MiB - 900000 signals
1000000 - 244.98 MiB - 1000000 signals
1100000 - 285.09 MiB - 1100000 signals
1200000 - 265.71 MiB - 1200000 signals
1300000 - 265.71 MiB - 1300000 signals
1400000 - 311.45 MiB - 1400000 signals
1500000 - 378.47 MiB - 1500000 signals
1600000 - 377.95 MiB - 1600000 signals
1700000 - 378.01 MiB - 1700000 signals
1800000 - 378.65 MiB - 1800000 signals
1900000 - 406.42 MiB - 1900000 signals
2000000 - 423.68 MiB - 2000000 signals
2100000 - 503.71 MiB - 2100000 signals
2200000 - 503.72 MiB - 2200000 signals
2300000 - 464.14 MiB - 2300000 signals
2400000 - 464.20 MiB - 2400000 signals
2500000 - 464.20 MiB - 2500000 signals
2600000 - 464.20 MiB - 2600000 signals
2700000 - 481.40 MiB - 2700000 signals
2800000 - 548.31 MiB - 2800000 signals
2900000 - 611.93 MiB - 2900000 signals
3000000 - 678.66 MiB - 3000000 signals
3100000 - 685.27 MiB - 3100000 signals
3200000 - 685.36 MiB - 3200000 signals
3300000 - 685.36 MiB - 3300000 signals
3400000 - 685.36 MiB - 3400000 signals
3500000 - 685.36 MiB - 3500000 signals
3600000 - 686.01 MiB - 3600000 signals
3700000 - 686.08 MiB - 3700000 signals
3800000 - 748.08 MiB - 3800000 signals
3900000 - 775.59 MiB - 3900000 signals
...
Additional information
It's pretty clear that AbortSignal.any
attaches the combined signal to all its parent signals. But it only gets removed if the parent signals are actually aborted. If there is a long living signal among the parents, for instance something like a SIGINT handler, then it keeps accumulating WeakRefs to no longer existing AbortSignal
s.
Related issues:
- Related deno issue: AbortSignal.any() leaks when any of the provided signal is long-lived denoland/deno#24842
- Partly related issue: AbortSignal.any() not destroyed when goes out of scope #48419
- Particularly case 3 of AbortSignal.any() not destroyed when goes out of scope #48419 (comment)
- Different issue: AbortController/AbortSignal memory leak #55328
- Another leak when not properly removing listeners from
AbortSignal
returned byAbortSignal.any
- Another leak when not properly removing listeners from
- Probably not an issue at all: AbortSignal.any() causes memory leak #54614
Metadata
Metadata
Assignees
Labels
abortcontrollerIssues and PRs related to the AbortController APIIssues and PRs related to the AbortController APIconfirmed-bugIssues with confirmed bugs.Issues with confirmed bugs.