【问题标题】:Backbone.js Memory Management, Rising DOM Node CountBackbone.js 内存管理,上升的 DOM 节点数
【发布时间】:2013-02-14 02:25:11
【问题描述】:

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

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

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

问题

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

我真的只是在寻找阻止这些 DOM 节点上升的冒险的开始。任何帮助或指导将不胜感激(并相应地赞成)。

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

测试


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

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

  • 第二次测试:7.1 分钟,141,000 个 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。

【问题讨论】:

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


    【解决方案1】:

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

    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

    【讨论】:

      【解决方案2】:

      已经解决了! - 升级骨干。 (继续阅读)

      我们从 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

      【讨论】:

        【解决方案3】:

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

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

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

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

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

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

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

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

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

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

        【讨论】:

        • 谢谢,我会尽快调查此事,并提供进展/结果。
        【解决方案4】:

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

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

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

        This post 可能对你来说也很有趣。

        【讨论】:

        • 谢谢,我会尽快调查一下,然后将我的结果回复给您。目前正在运行压力测试,我的 DOM 节点数 > 180 万,而事件侦听器数保持在 40-450 的范围内,但通常在 40 到 275 之间。
        • 其实不用等那么久。如果页面有泄漏,它肯定会使渲染器进程因 OOM 崩溃。
        • 您可以使用 3-snapshot 技术并在 5 分钟内获取泄漏对象的列表,或者等待一个小时并在单个快照中查找最大的内存消耗。
        猜你喜欢
        • 1970-01-01
        • 2013-03-19
        • 1970-01-01
        • 2020-05-28
        • 1970-01-01
        • 2015-03-16
        • 2013-02-06
        • 1970-01-01
        • 2014-07-06
        相关资源
        最近更新 更多