Backbone.js内存管理,DOM节点数上升

时间:2013-02-28 02:17:20

标签: javascript backbone.js google-chrome-devtools mustache zepto

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

应用程序:应用程序构建于Backbone(mv *),Zepto(类似于jquery),Curl(amd loader)& Mustache(模板)。

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

问题

  • 是否有一种正确的方法来处理DOM节点,以便它们被正确地垃圾收集,或者这个DOM节点计算一个永不减少的运行总计?
  • 是否有人知道任何这些框架处理DOM节点?可能是小胡子?
  • DOM节点是否算是一个可靠的数字?

我真的只是想在冒险中找到一个好头来阻止这些DOM节点上升。任何帮助或指导将不胜感激(并相应地投票)。

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

测试


Poorly Managed DOM Node Count

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

编辑:在没有时间轴录制的情况下,我重新使用相同的脚本来随机混搭链接并在7分钟左右拍摄截图。 GC发布后我得到了这些结果。

Poorly Managed DOM Node Count

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

编辑:修复后

DOM Node Count under control 升级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 个答案:

答案 0 :(得分:9)

  

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

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

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

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

要确保可以对垃圾收集DOM节点进行垃圾收集,

  1. 从文档树中删除节点。
  2. 清除从javascript到节点 AND 的所有引用到同一子树中的所有节点,从javascript引用到子树中的一个节点将保留整个子树。
  3. 因此仅从节点中删除侦听器以使其可收集是不够的。此外,如果您希望收集节点,则不一定从节点中删除侦听器。

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

      
        
    • DOM节点是否算是一个可靠的数字?
    •   

    是。它应该是一个可靠的数字,因为它在创建新DOM节点时递增,在销毁时递减。所以相信它的实现非常简单。

答案 1 :(得分:6)

这是固定的! - UPGRADE BACKBONE。 (继续阅读)

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

运行相同的压力测试7分钟后,结果如下: enter image description here

结果: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

答案 2 :(得分:3)

上升的DOM节点数是内存泄漏的主要标志(通常在我们页面的代码中)。 所以你需要对抗它。标准技术在this question.

的答案中描述

快照内容包含太多详细信息。这3个快照模式可以帮助您过滤掉快照中没有意思的部分,并仅显示泄漏的候选者。

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

This post对你也很有意思。

答案 3 :(得分:0)

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

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