setTimeout()如何在此代码中创建内存泄漏?

Med*_*Man 5 javascript memory-leaks

我正在审查此演示文稿中的幻灯片:http://slid.es/gruizdevilla/memory

在其中一张幻灯片中,此代码显示它会创建内存泄漏:

var buggyObject = {
   callAgain: function() {
     var ref = this;
     var val = setTimeout(function() {
        ref.callAgain();
     }, 1000);
   }
}

buggyObject.callAgain();
buggyObject = null;
Run Code Online (Sandbox Code Playgroud)

有人可以在这里更详细地解释这个问题吗?我可能会在这里遗漏一些细微之处.

adv*_*ncd 6

这肯定是内存泄漏.但是,内存消耗很小,无法测量.我对源代码做了一些小改动.

  • 我将整个代码放在循环中以创建相同的场景100,000次
  • 我将计时器间隔增加到大约16分钟.这可以防止浏览器崩溃

这是代码:

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;
}
Run Code Online (Sandbox Code Playgroud)

Chrome中的内存泄漏

我的实验:

我在Chrome版本34.0.1847.116 m中运行了代码,并使用Developer Tools\Timeline捕获了内存更改.

正如我们在图片中看到的,运行此代码已经消耗了大约32 MB的内存,一段时间后它已经减少到大约30 MB并保持不变(参见#1).经过Chrome的几次垃圾收集尝试(参见#2)和我的一次手动强制垃圾收集(参见#3,#4),内存消耗保持不变.没有更多buggyObject,我们无法释放内存.唯一可行的方法是关闭浏览器.

是什么导致这个?

这种行为的主要原因是计时器.定时器回调及其绑定对象,buggyObject在超时发生之前不会被重新启动.在我们的情况下,计时器重置自己并永远运行,因此即使没有对原始对象的引用,也不会收集其内存空间.


Ste*_*ert 5

还有另一个问题描述了setTimeout()看起来如何有内存泄漏,但实际上并没有.

但是,我认为作者试图说的是,因为buggyObject创建了一个调用自身的setTimeout,即使你将buggyObject更改为相等null(说你完成了对象并且可以清理它),该对象也不会收集垃圾,因为在setTimeout()中仍然有对它的引用.这在技术上是一个内存泄漏,因为不再有任何对setTimeout函数的直接引用,以便您以后可以清除它(如果你愿意,可以使用某种类型的僵尸超时).