情况:我正在制作一个相当复杂的单页Backbone应用,可能会连续运行8-12个小时。因此,需要确保应用程序不会泄漏,并且在X小时后崩溃或显着减速的声誉。
应用程序:应用程序构建于Backbone(mv *),Zepto(类似于jquery),Curl(amd loader)& Mustache(模板)。
问题:我刚刚征服了事件监听器。垃圾收集器似乎在清理这些人员方面做得很好,但DOM节点计数不会停止攀爬。
问题:
我真的只是想在冒险中找到一个好头来阻止这些DOM节点上升。任何帮助或指导将不胜感激(并相应地投票)。
我假设一旦事件监听器被妥善处理,DOM节点计数就会自行管理,但情况似乎并非如此。
编辑:在没有时间轴录制的情况下,我重新使用相同的脚本来随机混搭链接并在7分钟左右拍摄截图。 GC发布后我得到了这些结果。
编辑:修复后:
升级Backbone并使用listenTo和stopListening无处不在
答案 0 :(得分:9)
我假设一旦事件监听器被妥善处理,DOM节点计数就会自行管理,但情况似乎并非如此。
如果我说得对,你试图通过从中删除侦听器来处理节点,是这样吗?
请注意,向DOM节点添加事件侦听器不会阻止节点被垃圾回收,依赖性方向相反:当节点处于活动状态时,将不会收集侦听器函数。
- 是否有正确的方法来处理DOM节点以便它们被正确地垃圾收集,或者这个DOM节点计数是一个永不减少的运行总计?
要确保可以对垃圾收集DOM节点进行垃圾收集,
因此仅从节点中删除侦听器以使其可收集是不够的。此外,如果您希望收集节点,则不一定从节点中删除侦听器。
当GC收集某些节点并销毁时,DOM节点数应该减少。该数字表示已创建但未销毁的DOM节点的当前数量,因此除非存在内存泄漏,否则它不应无限增长。
- DOM节点是否算是一个可靠的数字?
是。它应该是一个可靠的数字,因为它在创建新DOM节点时递增,在销毁时递减。所以相信它的实现非常简单。
答案 1 :(得分:6)
这是固定的! - UPGRADE BACKBONE。 (继续阅读)
运行相同的压力测试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
答案 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