如何在没有内存泄漏的情况下删除DOM元素?

时间:2010-09-24 08:09:20

标签: javascript jquery dom memory-leaks

我的JavaSript代码构建了LI个元素的列表。当我更新列表时,内存使用量会增长,永远不会下降。我在sIEve中进行了测试,它显示浏览器保留了应该被$.remove()$.empty jQuery命令删除的所有元素。

如何在没有内存泄漏的情况下删除DOM节点?

有关具体代码,请参阅my other question

5 个答案:

答案 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#removejQuery#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

或者使用此闭包修复解决方法:

http://laurens.vd.oever.nl/weblog/items2005/closures/