[英]Why does closure cause memory leak in JavaScript in this case?
我有以下代码片段:
function outer() {
let a
return function inner() {
a = new Uint8Array(100000)
const b = new Uint16Array(100000)
};
};
const fn = outer();
fn()
拍摄了一个堆快照,在 chrome 103.0.5060.114 的 about:blank 页面中运行它,然后拍摄了第二张快照。 比较两个快照,我发现在第二个快照中,多了一个Uint8Array
。 这意味着a
保留在内存中,所以它泄漏了 。 但我找不到任何Uint16Array
所以b
没有泄漏。
但我无法弄清楚为什么Uint8Array
会泄漏,因为我似乎仍然无法在outer
函数之外引用它。 所以按照垃圾回收算法,现在应该已经被回收了。
尚未在其他浏览器或 Node.js 中对此进行测试。
@ITgoldman 的解释是正确的: a
被保留是因为inner
使用它,并且fn === inner
,并且fn
仍然可以访问。 这不是泄漏。
a
可以在fn()
完成后再次调用fn()
再次到达。 b
只是一个局部变量,所以当fn()
返回时它超出了范围。
这是如何有用/需要的示例:考虑对您的代码段进行以下轻微修改:
function outer() {
let a = 0;
return function inner() {
a++;
console.log(`counter is now ${a}`);
};
};
const fn = outer();
fn()
fn()
fn()
显然,从fn()
的一次调用到下一次调用, a
应该保持活动状态,因此它不能被收集。
inner
/ fn
是从a
读取、写入a
还是两者都做并不重要。 只要它以任何方式使用a
,只要fn
存在, a
就会保持存在。 这是有道理的,因为可能有多个函数引用它:您可以让inner1
分配新数组并将它们存储在a
中,而inner2
对这些数组进行处理。
(这不是 V8 问题;所有符合规范的 JavaScript 引擎都必须这样做。)
通常,在函数调用完成后,词法环境连同所有变量一起从内存中删除。 那是因为没有引用它。 与任何 JavaScript 对象一样,它仅在可访问时保存在内存中。
但是,如果有一个嵌套函数在函数结束后仍然可以访问,那么它具有引用词法环境的 [[Environment]] 属性。
您可以在此处详细了解垃圾收集在闭包中的工作原理。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.