在闭包中引用DOM元素的IE内存泄漏?

时间:2011-04-18 20:59:44

标签: javascript internet-explorer dom

在最近的一次采访中,我被问到:“在引用DOM元素时使用闭包有什么危险,就像这个代码一样?”

var firstNameValue = (function(elementId) {
    var firstName = document.getElementById(elementId);
    return firstName.value;
})("firstName");

显然,我不知道,上面的代码在IE中创建了内存泄漏。给出的理由很模糊,我不明白,但显然这可能只适用于较旧的IE版本?

任何人都可以详细说明这个吗?

2 个答案:

答案 0 :(得分:5)

IE中用于处理由/为DOM分配的内存的垃圾收集器不知道如何释放可能由JScript引擎分配的内存。因此,它只是忽略了这些事情。

所以你将一个事件处理程序绑定到一个DOM元素(或类似的东西),你的事件处理程序是在一些其他函数的调用内创建的函数,而另一个函数有一个本地数组,里面有十亿个东西好吧,在DOM元素本身被废弃之后很久就存在了十亿个东西,甚至在包含它的页面之后很久就被释放了(我想;已经有一段时间了)。

function bindHandler(domElement) {
  var hoHumWhatever = generateGiganticObjectNow();

  domElement.onclick = function() {
    alert("oww you clicked me");
  };
}

现在在闭包中保留了“hoHumWhatever”变量。当重新加载页面或修改DOM以使元素被丢弃时,DOM垃圾收集器将无法对指向JScript拥有的内存的属性执行任何操作。另一方面,JScript不知道DOM节点已被释放,因此它认为仍然引用了闭包内存。

我承认在某些细节上这可能不准确,但这是基本问题。各种各样的人都写过这个,包括Crockford先生和(我认为)ppk在quirksmode。

编辑 - 在仔细阅读您发布的代码后,我认为可能是类似但相反情况的一个示例: little函数返回对DOM值的一部分的引用,所以也许有人说JScript将挂起到DOM内存(而不是反之亦然)。现在,在这种特殊情况下,我有点怀疑,因为除了对DOM属性的简单引用之外,我没有看到有什么东西从该闭包中“逃脱”,DOM属性应该是一个原始的字符串实例,所以它真的不应该引起问题。这些事情可能具有欺骗性,但我只会坐在这里划伤我的头脑。

答案 1 :(得分:4)

以下代码不会创建任何闭包(见下文)或内存泄漏。

var firstNameValue = (function(elementId) {
    var firstName = document.getElementById(elementId);
    return firstName.value; 
})("firstName");

使用IE 6进行的一些调查表明,代码不会造成内存泄漏。我添加了1000个带有大块 Lorem ipsum 和独特ID的div,然后根据上面的代码运行了1000个匿名函数,每次刷新页面时它都会在我打开之前顽固地返回到内存中使用它这页纸。即使向页面添加数千个元素超过100mb也没有让它失望,IE仍然恢复到原始大小。

所以要么这是一个技巧问题(即正确的答案是“没有持久性闭包且没有循环引用,因此没有内存泄漏”)或者任何想到它的人都没有正确写入。

如果这不是一个技巧问题,看看你是否可以得到任何人写这个问题,或者让问题给你一个实际的演示。

<强> 封闭

  

关闭的简单解释是   ECMAScript允许内部   功能;功能定义和   内部的函数表达式   其他功能的功能。   那些内在的功能是   允许访问所有本地   变量,参数和声明   内在的功能在他们的外部   功能)。闭合时形成   其中一个内部功能是   在函数外部可访问   包含它,以便它可以   在外部函数之后执行   已经回来了。它仍然存在   有权访问局部变量,   参数和内在功能   声明其外部功能。   那些局部变量,参数和   函数声明(最初)有   当他们拥有的价值观   返回外部函数,可能是   与内在的功能相互作用。

Richard Cornford等人,“ Javascript Closures ”,http://www.jibbering.com/faq/notes/closures/