【问题标题】:IE memory leak from referencing DOM elements in closures?在闭包中引用 DOM 元素导致 IE 内存泄漏?
【发布时间】:2011-08-08 04:57:26
【问题描述】:

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

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

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

谁能详细说明一下?

【问题讨论】:

  • 提问者要么很笨,要么很聪明。愚蠢,因为没有关闭或内存泄漏,整个事情相当于:var firstNameValue = document.getElementById('firtName').value;。或者非常聪明,因为提到关闭和内存泄漏会分散真正问题的注意力 - 代码不必要的复杂性。
  • 据报道,“内存泄漏问题”在 IE8 中已修复。但是,正如@RobG 在他的回答中所说,我看不出这可能如何导致旧浏览器中的内存泄漏。下面的 MSDN 页面列出了一系列在 IE7 和更早版本中会导致内存泄漏的测试用例 - 我没有看到包含这种模式。 msdn.microsoft.com/en-us/library/dd361842(VS.85).aspx

标签: javascript internet-explorer dom


【解决方案1】:

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

因此,您将事件处理程序绑定到 DOM 元素(或类似的东西),并且您的事件处理程序是在调用其他函数时创建的函数,并且该其他函数有一个本地数组,其中包含十亿个东西,好吧,在 DOM 元素本身被废弃之后,甚至在包含它的 页面 被释放很久之后(我认为;已经有一段时间了),这十亿东西仍然存在。 p>

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

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

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

我承认这在某些细节上可能不准确,但这是基本问题。很多人都写过这方面的文章,包括 Crockford 先生和(我认为)quirksmode 的 ppk。

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

【讨论】:

  • 谈谈“堆栈溢出”:)
  • 我同意你的观点,我需要看到它证明上述内容会造成泄漏。 没有闭包,“小函数”(被某些人称为 iife)不会持续存在,即使它存在,它也不会引用其外部范围内的任何变量(尽管它确实获得了对 DOM 元素的引用)。唯一可能的泄漏来自 DOM 引用,如果这会造成泄漏,那么您究竟如何避免它呢? IE 内存泄漏的主要问题是涉及 DOM 元素的循环引用(根据您的示例),但这已得到修复(据我所知)。
【解决方案2】:

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

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

对 IE 6 的一些调查表明该代码不会造成内存泄漏。我添加了 1,000 个 div,其中包含一大块 Lorem ipsum 和唯一 ID,然后按照上述代码运行 1000 个匿名函数,每次刷新页面时,它都会顽固地返回到我打开之前使用的内存这页纸。即使向页面添加数千个元素以超过 100mb 也不会影响它,IE 不断恢复到原始大小。

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

如果这不是一个技巧问题,请看看是否可以让编写它或提出问题的人给你一个实际演示。

关闭

闭包的简单解释是 ECMAScript 允许内部 职能;函数定义和 里面的函数表达式 其他功能的功能体。 而那些内在功能是 允许访问所有本地 变量、参数和声明 外在的内在功能 职能)。闭包形成时 这些内部功能之一是 可在函数之外访问 它被包含在内,以便它可以 在外部函数之后执行 已经回来了。在这一点上它仍然 可以访问局部变量, 参数和内部函数 其外部函数的声明。 那些局部变量、参数和 函数声明(最初)有 他们的价值观 外部函数返回,可能是 由内部函数进行交互。

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

【讨论】:

    猜你喜欢
    • 2021-08-02
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-11-21
    • 2013-07-25
    • 2010-09-28
    • 1970-01-01
    • 2012-02-07
    相关资源
    最近更新 更多