解决方法IE10的setInterval内存泄漏(Workaround for IE10 setIn

2019-08-20 23:43发布

在我们的Javascript库的测试中,我想我们找到了IE10的一个严重的内存泄漏(v10.0.9200.16519 - Windows 8的64位)Javascript实现的setInterval

一个简单的测试情况表明,如果一个变量的函数关闭捕捉传递的参数,以便以后执行它似乎没有以往任何时候都变得符合垃圾收集,即浏览器似乎仍然坚持函数的引用或至少封闭变量。

我们的测试用例执行setInterval功能只有一次,然后清除间隔定时器,没有代码被运行了一段时间后,即没有变量访问了(据我可以看到没有全局介绍了在这段代码中,除了方法在运行onload ),然而该过程占用的存储器亿字节(取决于迭代次数)。

有趣的是,如果我们使用这不会发生setTimeout方法,而不是(也似乎问题并不在IE9存在,和Chrome,FF的当前版本)。

这个问题可以看出这个小提琴 。

在IE10在Windows 8新的实例中运行它,打开任务管理器看内存使用情况。 它会迅速增长至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上的问题 )

更新:这个问题也存在于IE10在Windows 7上,但如果切换到IE9标准的模式不存在。 我提出这MS连接,并将报告进展情况。

更新:微软接受了问题并报告它被固定在IE11(预览版) -我没有这个确认自己,但(谁?)

更新:IE 11已经正式发布了,我不能在该版本与我的系统(赢8.1专业版64位)重现该问题了。

Answer 1:

为了完整起见,我在这里增加一个可能的解决方法:

正如我已经写了(和评论者建议),这可以通过回落到被合作周围(不固定) setTimeout 。 这是不平凡的,因为一些ID簿记需要做的事情。 这里是我建议的修复,您可以测试并从这个小提琴叉 :

var registerSetIntervalFix = function(){
    var _setTimeout = window.setTimeout;
    var _clearTimeout = window.clearTimeout;
    window.setInterval = function(fn, interval){
        var recurse = function(){
            var newId = _setTimeout(recurse, interval);
            window.setInterval.mapping[returnValue] = newId;
            fn();
        }
        var id = _setTimeout(recurse, interval);
        var returnValue = id;
        while (window.setInterval.mapping[returnValue]){
            returnValue++;
        }
        window.setInterval.mapping[returnValue] = id;
        return returnValue;
    }
    window.setInterval.mapping = {};
    window.clearInterval = function(id){
        var realId = window.setInterval.mapping[id];
        _clearTimeout(realId);
        delete window.setInterval.mapping[id];
    }
}

我们的想法是递归调用setTimeout模拟重复setInterval调用。 有在此实现一个小的开销,因为它必须执行簿记的改变id S,所以除非需要我不会推荐应用此修复程序。

可惜我没能拿出一个“功能”检测算法(更像是一个“错误” - 检测算法),所以我想你必须恢复到良好的旧浏览器检测。 另外我的实现不能处理字符串作为第一个参数,没有通过额外的参数传递给内部函数。 最后它是不安全的两次调用这个方法,所以需要您自担风险使用它(并随时改进它)!

(注:我们的图书馆,我们将停止使用setInterval从现在开始,而是重写依赖于它使用的代码的几个部分setTimeout直接。)



文章来源: Workaround for IE10 setInterval Memory Leak