【发布时间】:2013-04-01 02:27:13
【问题描述】:
在测试我们的 Javascript 库期间,我认为我们在setInterval 的 IE10(v10.0.9200.16519 - Windows 8 64 位)Javascript 实现中发现了严重的内存泄漏。
一个简单的测试用例表明,如果一个变量在作为参数传递的函数的闭包中被捕获以供以后执行,它似乎永远不适合垃圾收集,即浏览器似乎仍然持有对函数或至少是闭包变量。
我们的测试用例只执行一次setInterval 函数,然后清除间隔计时器,即一段时间后不再运行代码并且不再可访问变量(据我所知,此代码中没有引入全局变量,除了在onload 中运行的方法之外,该过程仍然占用了半 GB 的内存(取决于迭代次数)。
有趣的是,如果我们改用 setTimeout 方法,则不会发生这种情况(而且问题不似乎存在于 IE9 和当前版本的 Chrome、FF 中)。
问题可以通过this 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 调用?
(我也是posted the question on MSDN)
更新:此问题在 Windows 7 上的 IE10 中也存在,但如果您切换到 IE9 标准模式则不存在。我已将此提交给 MS Connect,并将报告进度。
更新: Microsoft accepted the issue 并报告它已在 IE11(预览版)中修复 - 我自己还没有确认这一点(有人吗?)
更新: IE 11 已经正式发布,我无法再用我的系统(Win 8.1 Pro 64bit)在那个版本上重现问题。
【问题讨论】:
-
为什么要创建一个间隔然后立即清除它?这不是违背了目的吗?
-
@BradM 我用解释更新了这个问题 - 真正的代码比这更复杂,并且并不总是无条件地清除间隔。
-
您是否尝试过不使用匿名函数,而是使用函数引用,然后显式覆盖此引用?
-
“如果我们使用 setTimeout 方法,这不会发生” - 那么,问题解决了吗?使用 setInterval 可以做的任何事情都可以通过重复的 setTimeout 调用来做,对吧?
-
@MarkBessey 是的,也不是 :-) 我的代码可以正常工作,是的,但实际问题(泄漏)没有解决。当然,我可以重写
setInterval实现——当然,我宁愿理解我的代码中的问题(如果有的话)或者在 IE 中修复它。这个问题得到的关注越多,修复的可能性就越大,未来受影响的人就越少。所以我讨厌称这个问题为“已解决”,尽管现在看起来,我会这样做。
标签: javascript internet-explorer memory-leaks