Skip to content

Commit

Permalink
fix: memory leak in finalization first appearing in v6.16.0 (#3445)
Browse files Browse the repository at this point in the history
* fix: memory leak

Holding a reference to the stream in the finalization registry causes a memory leak, even when consuming the body.

* docs: add comment explaining the strong reference

* typo
  • Loading branch information
snyamathi authored Aug 9, 2024
1 parent 8cda85b commit 00552bb
Showing 1 changed file with 9 additions and 3 deletions.
12 changes: 9 additions & 3 deletions lib/web/fetch/response.js
Original file line number Diff line number Diff line change
Expand Up @@ -34,8 +34,9 @@ const hasFinalizationRegistry = globalThis.FinalizationRegistry && process.versi
let registry

if (hasFinalizationRegistry) {
registry = new FinalizationRegistry((stream) => {
if (!stream.locked && !isDisturbed(stream) && !isErrored(stream)) {
registry = new FinalizationRegistry((weakRef) => {
const stream = weakRef.deref()
if (stream && !stream.locked && !isDisturbed(stream) && !isErrored(stream)) {
stream.cancel('Response object has been garbage collected').catch(noop)
}
})
Expand Down Expand Up @@ -526,7 +527,12 @@ function fromInnerResponse (innerResponse, guard) {
setHeadersGuard(response[kHeaders], guard)

if (hasFinalizationRegistry && innerResponse.body?.stream) {
registry.register(response, innerResponse.body.stream)
// If the target (response) is reclaimed, the cleanup callback may be called at some point with
// the held value provided for it (innerResponse.body.stream). The held value can be any value:
// a primitive or an object, even undefined. If the held value is an object, the registry keeps
// a strong reference to it (so it can pass it to the cleanup callback later). Reworded from
// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/FinalizationRegistry
registry.register(response, new WeakRef(innerResponse.body.stream))
}

return response
Expand Down

0 comments on commit 00552bb

Please sign in to comment.