使用适当的 GC 删除 DOM 节点(无泄漏)

Posted

技术标签:

【中文标题】使用适当的 GC 删除 DOM 节点(无泄漏)【英文标题】:Removing DOM nodes with proper GC (no leaks) 【发布时间】:2014-12-02 01:39:13 【问题描述】:

问题

添加节点,同时从 DOM 中删除旧节点,不会从内存中丢弃旧节点。 (至少不是全部,没有明显的原因)。

如何看待这种情况

(你已经知道了,但无论如何..) 右键单击输出区域并使用 Chrome 开发者工具进行检查。 点击时间线标签,然后点击左上角的圆圈(点)开始录制。

现在单击 body 元素,它将开始每隔 300 毫秒添加和删除项目 (删除的节点应该被垃圾收集)。

停止记录,将数据采样区域扩大到最大,您将在屏幕的下半部分看到绿色的节点。预期的图表会上下波动(下降意味着节点已被 GC 正确丢弃)。

测试页面

这两个测试页面非常原始。当然,在现实生活中开发人员使用的模板会生成大量文本,这些文本应该被转换成 DOM 并注入到页面中,因此内存中的活动 DOM 节点的数量应该保持在较低水平,并且必须移除那些 必须 被丢弃。

使用 jQuery - http://jsbin.com/lamigucuqogi/2/edit - 大约 40 秒后 GC 变得疯狂并停止收集已删除的节点,这会导致膨胀。

幼稚的方式 - http://jsbin.com/riref/2/edit - 似乎节点并没有以令人满意的速度被移除,而且数量还在不断增长......

问题

为什么会发生这种情况,应该如何正确删除 NODES 以免发生通货膨胀?

【问题讨论】:

我的机器上没有得到这个结果。你确定这不是比赛条件吗?您是否以更长的间隔得到相同的结果? 我已经尝试了 1 分钟。它达到 100,000 个节点。我认为在真正的应用程序中这会非常疯狂。我的意思是,为什么它们在被移除时不被收集?以及为什么在第一个示例中收集它们,然后神秘地停止收集。你看到了什么结果?他们被收集了吗? 哪个版本的chrome?我在 Chrome 37 64 位(Linux)上。是的,我的正在收集中。 版本 37.0.2062.124 m / Windows 7 64bit @squint - 有趣。你能把你的图表贴在这里吗? snapnote.io 【参考方案1】:

你错了。如果您让示例运行很长时间,然后使用 Dev Tools 时间线中的垃圾桶图标强制进行垃圾收集,您将观察到节点已被释放。

与任何其他 javascript 对象一样,当 DOM 节点从 GC Roots 变得无法访问时,它们就有资格进行 GC。如果您不保留对已删除节点的任何其他引用(例如,在数组中),一旦从主文档中删除,它们就会变得无法访问。

但是,它们不会立即进行垃圾收集 - GC 运行可能需要一些时间,在此期间主浏览器线程被阻塞,因此它只会定期运行。您所看到的是 JavaScript 引擎决定不运行垃圾收集器的时期。您不必为此担心 - 您的代码确实允许垃圾收集器在最终运行时释放内存。

强烈推荐观看 - Addy Osmani's memory management masterclass。

【讨论】:

我不明白。为什么我要从开发工具中手动清理 GC?这不会证明什么。 GC 必须自己自动收集移除的 DOM 节点。另外,这不是答案,而是评论 您的前提似乎是删除的节点不是垃圾收集的。这可以通过触发手动 GC 事件来测试。执行此操作时,将收集已删除的节点。你的代码非常好。您不应该担心 何时 JS 引擎决定进行 GC,只需要您的代码使其能够在运行时有效地释放内存。这是一个答案,因为它说明问题不是由您的代码引起的,这可能会在将来为其他用户解决类似的问题。

以上是关于使用适当的 GC 删除 DOM 节点(无泄漏)的主要内容,如果未能解决你的问题,请参考以下文章

DOM节点删除之empty和remove

Python 2.7中的无内存泄漏OrderedDict替代方案?

节点数量增加,但堆比较显示没有分离的 dom,并且 dom 大小稳定

检测节点何时被删除(或因为父节点被从 DOM 中删除)

jQuery对DOM节点进行操作(删除节点)

jQuery对DOM节点进行操作(删除节点)