I have this following code snippet:
function outer() {
let a
return function inner() {
a = new Uint8Array(100000)
const b = new Uint16Array(100000)
};
};
const fn = outer();
fn()
Took one heap snapshot, ran it in a about:blank page in chrome 103.0.5060.114, and took a second snapshot. Comparing the two snapshots, I found that in the second snapshot, there is one more Uint8Array
. That means a
is retained in memory, so it leaked. But I can't find any Uint16Array
so b
didn't leak.
But I couldn't figure out why that Uint8Array
is leaking because it doesn't seem like I can still reference it outside the outer
function. So According to the garbage collection algorithm, it should have been collected by now.
Haven't tested this in other browsers or in Node.
CodePudding user response:
@ITgoldman's explanation is right: a
is retained because inner
uses it, and fn === inner
, and fn
is still reachable. This is not a leak.
a
can be reached again after fn()
finishes simply by calling fn()
again. b
is just a local variable, so it goes out of scope when fn()
returns.
An example how this is useful/required: consider the following slight modification of your snippet:
function outer() {
let a = 0;
return function inner() {
a ;
console.log(`counter is now ${a}`);
};
};
const fn = outer();
fn()
fn()
fn()
Clearly, a
should remain alive from one invocation of fn()
to the next, so it can't be collected.
It doesn't matter whether inner
/fn
reads from a
, writes to a
, or does both. As long as it uses a
in any way, a
will remain alive as long as fn
is alive. This makes sense because there could be more than one function referring to it: you could have inner1
allocating new arrays and storing them in a
, and inner2
doing stuff with these arrays.
(This is not a V8 question; all spec-compliant JavaScript engines are required to behave like this.)
CodePudding user response:
Usually, a Lexical Environment is removed from memory with all the variables after the function call finishes. That’s because there are no references to it. As any JavaScript object, it’s only kept in memory while it’s reachable.
However, if there’s a nested function that is still reachable after the end of a function, then it has [[Environment]] property that references the lexical environment.
You can more about how garbage collection works in closures here.