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

IT技术 javascript jquery dom memory-leaks
2021-03-01 00:55:38

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

我应该怎么做才能在没有内存泄漏的情况下删除 DOM 节点?

具体代码我的其他问题

5个回答

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);
是否需要将垃圾箱添加到文档正文中?
2021-04-21 00:55:38
我不知道“DOM 保留所有 DOM 节点,即使它们已从 DOM 树本身中删除”你的意思是 $.remove() 函数不做任何事情吗?
2021-04-28 00:55:38
这个答案令人困惑和模棱两可。它说页面刷新是删除节点的“唯一方法”,但它也暗示浏览器的垃圾收集将释放这些节点的内存。如果为真,则刷新不是“唯一”的方式。此外,从开发人员的角度来看,可以被垃圾回收的对象和已经被垃圾回收的对象之间应该没有区别——这是自动内存管理的重点——当 GC 运行时应该对垃圾不透明用户。
2021-05-01 00:55:38
在 sIEve 中测试后,我可以说它有助于删除垃圾节点。但是当我在 IE8 和 FF 中进行测试时,无论如何内存使用量都会增加。安德鲁, appendChild 做什么?将节点移动到垃圾 div?我应该在discadElement() 之前运行$.unbind() 吗?
2021-05-06 00:55:38
“DOM 保留所有 DOM 节点”是否意味着实现 DOM 规范的浏览器实际上将在 DOM 树之外存储对这些节点的引用,或者只是这些节点将在内存中徘徊直到下一次垃圾收集器运行?答案暗示后者,但是如果这些节点能够被垃圾收集,那么这些节点在任何意义上都不会“保留”。
2021-05-16 00:55:38

与其说是实际答案,不如说仅供参考,但它也很有趣。

来自 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:据我所知,除了Object从 DOM 中node删除 s 或nodedocument. 他们只删除 那当然并不意味着没有分配给这些对象的内存(即使它们document不再存在)。

编辑:上面的段落是多余的,因为显然 jQuery 不能创造奇迹并解决所用浏览器的 DOM 实现。

你说“据我所知,除了从 DOM 节点中删除对象或从文档中删除 DOM 节点之外,这些方法都没有做任何事情”..所以我从 API 中引用了它的功能。它还删除所有绑定事件。
2021-04-23 00:55:38
来自 jQuery .remove() API:“...除了元素本身,所有绑定事件和与元素关联的 jQuery 数据都被删除。要在不删除数据和事件的情况下删除元素,请改用 .detach()。”
2021-05-01 00:55:38
上下文是内存分配。但是哦,好吧,我在那里删除了jQuery.
2021-05-14 00:55:38

您是否删除了任何事件侦听器?会导致内存泄漏

谢谢@skilldrick!10 年后,你的建议让我走上了正确的道路(我在做 vanilla JS;不涉及 jQuery):-D
2021-04-27 00:55:38
我什至为每个元素做 $(this).unbind().html("").remove();
2021-05-04 00:55:38
我认为 jQuery 会在您执行 element.remove() 时自动删除事件处理程序,不是吗?
2021-05-04 00:55:38

下面的代码不会在我的 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

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

无泄漏 Javascript 关闭

固定关闭链接,使用网络存档
2021-04-27 00:55:38
我已经修复了 Crockford 链接,但我不知道另一个是什么
2021-05-05 00:55:38
两个链接都断开了;投反对票
2021-05-07 00:55:38