gpt4 book ai didi

闭包词法环境中的 JavaScript 内存泄漏

转载 作者:行者123 更新时间:2023-11-29 21:37:27 25 4
gpt4 key购买 nike

我试图理解为什么下面的代码会导致内存泄漏

var aThing = null;
var outer = function() {

console.log('running');
var something = aThing;

var closure1 = function() {
if (something) {
console.log('something');
}
};

aThing = {
str: new Array(1000000).join('8'),
someMethod: function() {}
};
};
setInterval(outer, 1000);

这是显示内存从 Google Chrome 增加的时间线:

Memory Leak

但是这段代码的微小变化不会导致相同的内存泄漏:

var aThing = null;
var outer = function() {

console.log('running');
var something = aThing;
var closure1 = function() {
if (something) {
console.log('something');
}
}

aThing = {
str: new Array(1000000).join('8')
};

function someMethod() {};
};
setInterval(outer, 1000);

这是显示 GC 清理正常的等效时间线。

No leak

我知道在第一个版本中存在内存泄漏,因为变量“something”没有被清理。为什么它在第二个示例中被 GC 而不是第一个?

最佳答案

主要的答案是,在您的第二个代码块中,没有直接引用任何一个闭包(closure1someMethod)在 outer< 的返回后仍然存在(outer 之外的任何内容都指向它们),因此没有任何内容指向创建它们的上下文,并且可以清除该上下文。但是,在您的第二个代码块中,对 someMethod 的直接引用在返回后仍然存在,作为您分配给 aThing 的对象的一部分,因此上下文作为整体不能被 GC。

让我们看看您的第一个区 block 会发生什么:

在第一次执行 outer 之后,我们有(忽略一堆细节):

            +−−−−−−−−−−−−−+aThing−−−−−>| (object #1) |                 +−−−−−−−−−−−−−+                 | str: ...    |     +−−−−−−−−−−−−−−−−−−−−+            | someMethod  |−−−−>| (context #1)       |            +−−−−−−−−−−−−−+     +−−−−−−−−−−−−−−−−−−−−+                                | something: null    |                                | closure1: function |                                +−−−−−−−−−−−−−−−−−−−−+

第二次执行后:

            +−−−−−−−−−−−−−+aThing−−−−−>| (object #2) |                 +−−−−−−−−−−−−−+                 | str: ...    |     +−−−−−−−−−−−−−−−−−−−−+                 | someMethod  |−−−−>| (context #2)       |                 +−−−−−−−−−−−−−+     +−−−−−−−−−−−−−−−−−−−−+     +−−−−−−−−−−−−−+                                                           | something          |−−−−>| (object #1) |                                                           | closure1: function |     +−−−−−−−−−−−−−+                                                           +−−−−−−−−−−−−−−−−−−−−+     | str: ...    |     +−−−−−−−−−−−−−−−−−−−−+                                                           | someMethod  |−−−−>| (context #1)       |                                                           +−−−−−−−−−−−−−+     +−−−−−−−−−−−−−−−−−−−−+                                                                               | something: null    |                                                                               | closure1: function |                                                                               +−−−−−−−−−−−−−−−−−−−−+

第三次执行之后:

            +−−−−−−−−−−−−−+aThing−−−−−>| (object #3) |                 +−−−−−−−−−−−−−+                 | str: ...    |     +−−−−−−−−−−−−−−−−−−−−+                 | someMethod  |−−−−>| (context #3)       |                 +−−−−−−−−−−−−−+     +−−−−−−−−−−−−−−−−−−−−+     +−−−−−−−−−−−−−+                                                                                                          | something          |−−−−>| (object #2) |                                                                                                          | closure1: function |     +−−−−−−−−−−−−−+                                                                                                          +−−−−−−−−−−−−−−−−−−−−+     | str: ...    |     +−−−−−−−−−−−−−−−−−−−−+                                                                                                          | someMethod  |−−−−>| (context #2)       |                                                                                                          +−−−−−−−−−−−−−+     +−−−−−−−−−−−−−−−−−−−−+     +−−−−−−−−−−−−−+                                                                                                          | something          |−−−−>| (object #1) |                                                                                                          | closure1: function |     +−−−−−−−−−−−−−+                                                                                                          +−−−−−−−−−−−−−−−−−−−−+     | str: ...    |     +−−−−−−−−−−−−−−−−−−−−+                                                                                                          | someMethod  |−−−−>| (context #1)       |                                                                                                          +−−−−−−−−−−−−−+     +−−−−−−−−−−−−−−−−−−−−+                                                                                                                              | something: null    |                                                                                                                              | closure1: function |                                                                                                                              +−−−−−−−−−−−−−−−−−−−−+

你可以看到这是怎么回事。

由于第二个 block 从不保留对 closure1someMethod 的引用,因此它们都不会在内存中保留上下文。

最初在 2015 年回答您的问题时,我有点惊讶 V8(Chrome 的 JavaScript 引擎)没有优化这个泄漏,因为只保留了 someMethod,而 someMethod 实际上并没有使用 somethingclosure1(或 evalnew Functiondebugger)。虽然理论上它通过上下文引用了它们,但静态分析会表明它们实际上无法使用,因此可以删除。但是闭包优化真的很容易被打扰,我猜里面有什么东西在打扰它,或者 V8 团队发现做那种级别的分析不值得运行时成本。我确实记得看到来自 V8 团队之一的推文说它过去比现在做更多的闭包优化(这次编辑是在 2021 年 9 月),因为这种权衡是不值得的。

关于闭包词法环境中的 JavaScript 内存泄漏,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/34480663/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com