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

发布于 2025-02-13 19:02:16 字数 929 浏览 0 评论 0原文

我有以下代码段:


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中的空白页面上运行,并拍摄了第二个快照。比较了两个快照,我发现在第二个快照中,有一个 uint8array 。这意味着a保留在内存中,因此泄漏。但是我找不到任何uint16Array SO b没有泄漏。

,但我无法弄清楚为什么uint8array泄漏,因为它似乎没有就像我仍然可以在外部函数之外引用它。因此,根据垃圾收集算法的说法,现在应该已经收集了它。

尚未在其他浏览器或节点中对此进行测试。

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.
enter image description here
enter image description here

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.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

习惯成性 2025-02-20 19:02:16

@itgoldman的解释是正确的:a由于Inner使用它而被保留,并且fn ==== Innerfn fn 仍然可以达到。这不是泄漏。

a可以在fn()完成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()

必需它不能收集。

Inner/fna读取,写入a还是两者都不重要,这没关系。只要使用 a以任何方式,只要fn还活着, a 就会保持生命。这是有道理的,因为可能有多个函数参考它:您可以将innect1分配新数组并将它们存储在a中,innion2用这些阵列做事。

(这不是V8问题;所有符合规格的JavaScript引擎都必须这样的行为。)

@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.)

烟酒忠诚 2025-02-20 19:02:16

通常,将词汇环境从内存中删除
函数调用完成后的变量。那是因为有
没有参考。作为任何JavaScript对象,它仅保留在
记忆虽然可以到达。

但是,如果有一个嵌套功能,仍然可以在
功能的结束,然后具有[[环境]]属性
参考词汇环境。

您可以详细介绍垃圾收集在关闭中的工作方式在这里

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.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文