15

情况:我正在开发一个相当复杂的单页 Backbone 应用程序,它可能会连续运行 8-12 小时以上。因此,需要确保应用程序不会泄漏,并且会因 X 小时后崩溃或显着减速而享有盛誉。

应用程序:该应用程序基于Backbone (mv*)、Zepto(类似于 jquery)、Curl(amd 加载器)和Mustache(模板)构建。

问题:我刚刚征服了事件监听器。垃圾收集器似乎在清理这些家伙方面做得很好,但 DOM 节点数不会停止攀升。

问题

  • 是否有适当的方法来处理 DOM 节点,以便正确地对它们进行垃圾收集,或者这个 DOM 节点计数是一个永远不会减少的运行总数?
  • 有谁知道这些框架中的任何一个不能很好地处理 DOM 节点?可能是胡子?
  • DOM Node Count 是一个可靠的数字吗?

我真的只是在寻找阻止这些 DOM 节点上升的冒险的开始。任何帮助或指导将不胜感激(并因此受到支持)。

我假设一旦事件侦听器被正确处理,DOM 节点计数就会自行管理,但情况似乎并非如此。

测试


管理不善的 DOM 节点数

  • 第一次测试:6.8 分钟,110,000 个 DOM 节点

编辑:在没有时间线记录的情况下,我重新运行相同的脚本以随机混搭链接,并在大约 7 分钟时截取了屏幕截图。GC通过后,我得到了这些结果。

管理不善的 DOM 节点数

  • 第二次测试:7.1 分钟,141,000 个 DOM 节点(没有时间线记录)

编辑:修复后

DOM 节点数受控制 升级 Backbone 并在各处使用 listenTo 和 stopListening

  • 7 分钟:6,926 个 DOM 节点(请参阅下面的标记答案)。
  • 20 分钟:6,000 个 DOM 节点,20 个事件监听器,内存 20 MB。
  • 25 分钟:11,600 个 DOM 节点,44 个监听器,内存 21.7 MB。
  • 28 分钟:9,000 个 DOM 节点,22 个事件监听器,内存 21.7 MB。
  • 30 分钟:13,700 个 DOM 节点,123 个事件监听器,内存 21.7。
  • 31 分钟:7,040 个 DOM 节点,30 个监听器,内存 21.7。
4

4 回答 4

9

我假设一旦事件侦听器被正确处理,DOM 节点计数就会自行管理,但情况似乎并非如此。

如果我说得对,您正试图通过从中删除侦听器来处理节点,是这样吗?

请注意,将事件侦听器添加到 DOM 节点并不会阻止该节点被垃圾收集,依赖是相反的方向:当节点处于活动状态时,侦听器函数将不会被收集。

  • 是否有适当的方法来处理 DOM 节点,以便正确地对它们进行垃圾收集,或者这个 DOM 节点计数是一个永远不会减少的运行总数?

为了确保 DOM 节点可以被垃圾收集,你应该

  1. 从文档树中删除节点。
  2. 清除从 javascript 到节点的所有引用以及对同一子树中所有节点的引用因为从 javascript 到子树中某个节点的引用将保留整个子树。

因此,仅从节点中删除侦听器以使其可收集是不够的。此外,如果您希望收集节点,则无需从节点中删除侦听器。

当一些节点被 GC 收集并销毁时,DOM 节点数应该会减少。该数字表示当前已创建但未销毁的 DOM 节点数量,因此它不应无限增长,除非存在内存泄漏。

  • DOM Node Count 是一个可靠的数字吗?

是的。它应该是一个可靠的数字,因为每当创建一个新的 DOM 节点时它就会增加,而当它被销毁时它会减少。因此,实现非常简单,可以信任它。

于 2013-02-28T08:27:06.710 回答
6

它是固定的!- 升级骨干。(继续阅读)

我们从 Backbone 0.9.2 升级到 Backbone 0.9.10,并在每个视图/模型/集合上实现了 listenTo 和 stopListening。结果是 OMGFANTASTIC 的。

运行相同的压力测试 7 分钟后,结果如下: 在此处输入图像描述

结果:7.0 分钟,6,926 个 DOM 节点(没有时间线记录)和事件侦听器计数看起来像BLUE BLADES OF GRASS。我感到震惊。与之前的测试相比,内存使用率也低得惊人。

18 分钟后:事件侦听器计数相同,从未超过 154,并且 DOM 节点计数始终低于 25,000!显然有一些东西漏掉了(很可能一些仍在使用的非骨干组件),但改进是惊人的。

结论:在此版本的 Backbone 之前,我们在 Backbone 本身内清理侦听器方面做得不是很好。DOM 的侦听器处理得很好,但不是在模型/视图/集合之间。许多涉及的回调都与 Backbone Views 相关联,我猜这会阻止垃圾收集器释放 DOM 节点。Backbone 中的大量散乱的事件侦听器/回调(不仅仅是绑定到 DOM)创建了许多不能被垃圾收集的散乱的 DOM 节点。

如果这还不是升级 Backbone 的充分理由,我不知道是什么;o

于 2013-03-13T00:38:28.893 回答
3

上升的 DOM 节点数是内存泄漏的主要标志(通常在我们页面的代码中)。所以你需要与之抗争。该问题的答案中描述了标准技术

快照内容有太多细节。这 3 个快照模式可帮助您过滤掉快照中不感兴趣的部分,并仅显示泄漏的候选者。

请确保您运行的是最新版本的 chrome,例如 Chrome Canary。它应该是一个没有扩展名的带有单个选项卡的新实例。最好在控制台中没有错误消息,没有断点并且不要在异常上停止,因为所有这些事情都可能影响页面并因此影响快照内容。

这篇文章对你来说可能也很有趣。

于 2013-02-28T05:47:14.383 回答
0

我找到了另一种避免卡顿的方法

render: function() {
  this.$el.empty();
  var container = document.createDocumentFragment();
  // render each subview, appending to our root element
  _.each(this._views, function(subview) {
     container.appendChild(subview.render().el)
  });
  this.$el.append(container);
}

在此处参考http://ozkatz.github.io/avoiding-common-backbonejs-pitfalls.html

于 2014-01-24T02:19:45.257 回答