在测试我们的 Javascript 库期间,我认为我们在setInterval
.
一个简单的测试用例表明,如果一个变量在作为参数传递的函数的闭包中被捕获,以供以后执行,它似乎永远不会有资格进行垃圾收集,即浏览器似乎仍然持有对该函数的引用或至少是闭包变量。
我们的测试用例setInterval
只执行一次函数,然后清除间隔计时器,即一段时间后不再运行代码,也不再可访问变量(据我所知,此代码中没有引入全局变量,除了运行方法in onload
),但是该过程占用了半 GB 的内存(取决于迭代次数)。
有趣的是,如果我们改用该方法,则不会发生这种情况setTimeout
(而且在 IE9 和当前版本的 Chrome、FF 中似乎不存在该问题)。
这个 fiddle可以看出问题。
在 Windows 8 上的全新 IE10 实例中运行它并打开任务管理器以查看内存使用情况。它将快速增长到 350 兆字节,并且在脚本执行后将保持在那里。
这是有问题的代码片段的重要部分:
// the function that when called multiple times will cause the leak in IE10
var eatMemory = function() {
var a = null; // the captured closure variable
var intervalId = setInterval(function() {
a = createBigArray(); // call a method that allocates a lot of memory
clearInterval(intervalId); // stop the interval timer
}, 100);
}
(我知道修复这段特定的代码很容易。但这不是重点——这只是我们想出的重现问题的最小的一段代码。真正的代码实际上是this
在闭包中捕获的,那个对象是从不收集垃圾。)
我们的代码中是否存在错误,或者是否有一种方法可以使用setInterval
闭包变量保存对大对象的引用而不会触发内存泄漏并且不会恢复到“递归”setTimeout
调用?
(我也在MSDN 上发布了这个问题)
更新: Windows 7 上的 IE10 中也存在此问题,但如果您切换到 IE9 标准模式,则不存在此问题。我将此提交给 MS Connect,并将报告进度。
更新: Microsoft接受了该问题并报告它已在 IE11(预览版)中修复 - 我自己还没有确认这一点,但(有人吗?)
更新: IE 11 已正式发布,我无法再用我的系统(Win 8.1 Pro 64bit)在该版本上重现该问题。