我的 JavaSript 代码构建了一个LI
元素列表。当我更新列表时,内存使用量会增加并且永远不会减少。我在 sIEve 中进行了测试,它显示浏览器保留了应该由$.remove()
或$.empty
jQuery 命令删除的所有元素。
我应该怎么做才能在没有内存泄漏的情况下删除 DOM 节点?
具体代码见我的其他问题。
我的 JavaSript 代码构建了一个LI
元素列表。当我更新列表时,内存使用量会增加并且永远不会减少。我在 sIEve 中进行了测试,它显示浏览器保留了应该由$.remove()
或$.empty
jQuery 命令删除的所有元素。
我应该怎么做才能在没有内存泄漏的情况下删除 DOM 节点?
具体代码见我的其他问题。
DOM 保留所有 DOM 节点,即使它们已从 DOM 树本身中删除,删除这些节点的唯一方法是进行页面刷新(如果您将列表放入 iframe 中,刷新将不会那么明显)
否则,您可以等待问题变得足够严重,以至于浏览器垃圾收集器被迫采取行动(此处讨论数百兆字节的未使用节点)
最佳实践是重用节点。
编辑:试试这个:
var garbageBin;
window.onload = function ()
{
if (typeof(garbageBin) === 'undefined')
{
//Here we are creating a 'garbage bin' object to temporarily
//store elements that are to be discarded
garbageBin = document.createElement('div');
garbageBin.style.display = 'none'; //Make sure it is not displayed
document.body.appendChild(garbageBin);
}
function discardElement(element)
{
//The way this works is due to the phenomenon whereby child nodes
//of an object with it's innerHTML emptied are removed from memory
//Move the element to the garbage bin element
garbageBin.appendChild(element);
//Empty the garbage bin
garbageBin.innerHTML = "";
}
}
要在您的上下文中使用它,您可以这样做:
discardElement(this);
这与其说是实际答案,不如说是仅供参考,但它也很有趣。
来自 W3C DOM 核心规范(http://www.w3.org/TR/DOM-Level-2-Core/core.html):
Core DOM API 旨在与多种语言兼容,包括通用用户脚本语言和专业程序员主要使用的更具挑战性的语言。因此,DOM API 需要在各种内存管理哲学中运行,从根本不向用户公开内存管理的语言绑定,到提供显式构造函数但提供自动垃圾收集机制的那些(特别是 Java)回收未使用的内存,用于那些(尤其是 C/C++)通常需要程序员显式分配对象内存、跟踪它的使用位置并显式释放它以供重用的内存。为了确保跨这些平台的 API 一致,DOM 根本不解决内存管理问题,而是将这些问题留给实现。DOM API(针对 ECMAScript 和 Java)定义的显式语言绑定都不需要任何内存管理方法,但其他语言(尤其是 C 或 C++)的 DOM 绑定可能需要这种支持。这些扩展将由那些使 DOM API 适应特定语言的人负责,而不是 DOM 工作组。
换句话说:内存管理留给了 DOM 规范在各种语言中的实现。您必须查看 javascript 中 DOM 实现的文档,以找出从内存中删除 DOM 对象的任何方法,这不是黑客。(然而,关于该主题的 MDC 站点上的信息很少。)
作为一个注释jQuery#remove
和jQuery#empty
:据我所知,除了Object
从 DOM 中node
删除 s 或node
从document
. 他们只删除 那当然并不意味着没有分配给这些对象的内存(即使它们document
不再存在)。
编辑:上面的段落是多余的,因为显然 jQuery 不能创造奇迹并解决所用浏览器的 DOM 实现。
您是否删除了任何事件侦听器?这会导致内存泄漏。
下面的代码不会在我的 IE7 和其他浏览器上泄漏:
<html>
<head></head>
<body>
<a href="javascript:" onclick="addRemove(this)">add</a>
<ul></ul>
<script>
function addRemove(a) {
var ul = document.getElementsByTagName('UL')[0],
li, i = 20000;
if (a.innerHTML === 'add') {
while (i--) {
li = document.createElement('LI');
ul.appendChild(li);
li.innerHTML = i;
li.onclick = function() {
alert(this.innerHTML);
};
}
a.innerHTML = 'remove';
} else {
while (ul.firstChild) {
ul.removeChild(ul.firstChild);
}
a.innerHTML = 'add';
}
}
</script>
</body>
</html>
也许您可以尝试发现您的代码的一些差异。
我知道在对 DOM 执行任何操作之前先将节点插入 DOM 时,IE 泄漏要少得多,例如:将事件附加到它或填充其innerHTML
属性。
如果您必须“后修复”泄漏,并且必须在不重写所有代码以考虑闭包、循环引用等的情况下这样做,请在删除之前使用 Douglas Crockfords Purge-method:
https://crockford.com/javascript/memory/leak.html
或使用此关闭修复解决方法: