我的JavaSript代码构建了LI
个元素的列表。当我更新列表时,内存使用量会增长,永远不会下降。我在sIEve中进行了测试,它显示浏览器保留了应该被$.remove()
或$.empty
jQuery命令删除的所有元素。
如何在没有内存泄漏的情况下删除DOM节点?
有关具体代码,请参阅my other question。
答案 0 :(得分:44)
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);
答案 1 :(得分:13)
这更像是一个 FYI 而不是一个实际答案,但它也很有趣。
来自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
的说明:从我所知道的这些方法中除了从DOM Object
中删除node
之外,其他任何方法都没有做或从node
删除DOM document
。它们只删除当然并不意味着没有分配给这些对象的内存(即使它们不再在document
中)。
编辑:以上段落是多余的,因为显然jQuery无法创造奇迹并解决使用过的浏览器的DOM实现。
答案 2 :(得分:8)
您是否删除了任何事件监听器?那can cause memory leaks。
答案 3 :(得分:2)
以下代码在我的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
属性。
答案 4 :(得分:1)
如果你必须“修复后”泄漏,并且必须这样做而不重写你的所有代码以便在帐户中使用闭包,循环引用等,请在删除之前使用Douglas Crockfords Purge-method:
http://javascript.crockford.com/memory/leak.html
或者使用此闭包修复解决方法: