繁体   English   中英

在这种情况下,为什么闭包会导致 JavaScript 中的内存泄漏?

[英]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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM