[英]How does setTimeout() create a memory leak in this code?
我正在查看本演示文稿中的幻灯片: http : //slid.es/gruizdevilla/memory
在其中一张幻灯片上,此代码显示了它会造成内存泄漏的建议:
var buggyObject = {
callAgain: function() {
var ref = this;
var val = setTimeout(function() {
ref.callAgain();
}, 1000);
}
}
buggyObject.callAgain();
buggyObject = null;
有人可以在这里更详细地解释这个问题吗? 我可能在这里遗漏了一些微妙之处。
这绝对是内存泄漏。 但是,内存消耗如此之小,无法衡量。 我对源代码做了一些小的改动。
这是代码:
for (var i = 0; i < 100000; i++) {
var buggyObject = {
callAgain: function() {
var ref = this;
var val = setTimeout(function() {
ref.callAgain();
}, 1000000); //16m
}
}
buggyObject.callAgain();
buggyObject = null;
}
我的实验:
我在Chrome 版本 34.0.1847.116 m 中运行代码并使用 Developer Tools\\Timeline 捕获内存更改。
正如我们在图片中看到的,运行这段代码消耗了大约 32 MB 的内存,一段时间后它减少到大约 30 MB 并保持不变(参见 #1)。 在 Chrome 尝试多次垃圾回收(参见 #2)和我手动强制垃圾回收(参见 #3、#4)之后,内存消耗保持不变。 不再有buggyObject
并且我们无法释放内存。 唯一可能的方法是关闭浏览器。
这是什么原因造成的?
这种行为的主要原因是计时器。 计时器回调及其绑定对象,直到超时发生才会释放 buggyObject。 在我们的例子中,定时器会重置自己并永远运行,因此即使没有对原始对象的引用,它的内存空间也永远不会被回收。
还有另一个问题描述了 setTimeout() 看起来如何有内存泄漏,但实际上并没有。
但是,我认为作者想说的是,由于buggyObject
创建了一个调用自身的 setTimeout,即使您将 buggyObject 更改为等于null
(说您已完成该对象并且可以对其进行清理),该对象也不会'不会被垃圾收集,因为在 setTimeout() 中仍然有对它的引用。 这在技术上是内存泄漏,因为不再有对 setTimeout 函数的任何直接引用,因此您可以稍后清除它(如果您愿意的话,这有点像僵尸超时)。
正如advncd 指出的那样,计时器被执行并在堆栈上添加更多数据。 对发生的事情有一个概念性的看法:
var a = 123;
// call the setTimeout.function
var a = 123;
// call the setTimeout.function
var a = 123;
// call the setTimeout.function
var a = 123;
// call the setTimeout.function
var a = 123;
// call the setTimeout.function
var a = 123;
// call the setTimeout.function
var a = 123;
// call the setTimeout.function
var a = 123;
// call the setTimeout.function
var a = 123;
...etc...
因此,每次在永远增长的堆栈上分配一个新变量a
。
然而,advncd 没有提到的是,您有一个 setInterval() 函数来完成您需要做的事情:一遍又一遍地调用相同的函数。 现在你仍然有一个“内存泄漏”,但只有初始化参数泄漏(即它不会在每次计时器超时时增长。)
所以从概念上讲,调用是平坦的,您可以避免泄漏:
a = 123;
// call the setTimeout.function
// call the setTimeout.function
// call the setTimeout.function
// call the setTimeout.function
// call the setTimeout.function
// call the setTimeout.function
// call the setTimeout.function
...etc...
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.