我创建了一个非常简单的测试用例,它创建一个 Backbone 视图,将一个处理程序附加到一个事件,并实例化一个用户定义的类。我相信通过单击此示例中的“删除”按钮,所有内容都会被清理干净,并且应该没有内存泄漏。
代码的 jsfiddle 在这里:http: //jsfiddle.net/4QhR2/
// scope everything to a function function main() { function MyWrapper() { this.element = null; } MyWrapper.prototype.set = function(elem) { this.element = elem; } MyWrapper.prototype.get = function() { return this.element; } var MyView = Backbone.View.extend({ tagName : "div", id : "view", events : { "click #button" : "onButton", }, initialize : function(options) { // done for demo purposes only, should be using templates this.html_text = "<input type='text' id='textbox' /><button id='button'>Remove</button>"; this.listenTo(this,"all",function(){console.log("Event: "+arguments[0]);}); }, render : function() { this.$el.html(this.html_text); this.wrapper = new MyWrapper(); this.wrapper.set(this.$("#textbox")); this.wrapper.get().val("placeholder"); return this; }, onButton : function() { // assume this gets .remove() called on subviews (if they existed) this.trigger("cleanup"); this.remove(); } }); var view = new MyView(); $("#content").append(view.render().el); } main();
但是,我不清楚如何使用谷歌浏览器的分析器来验证事实是否如此。堆分析器快照上显示了无数的东西,我不知道如何解码好/坏。到目前为止,我看到的教程要么只是告诉我“使用快照分析器”,要么给我一个关于整个分析器如何工作的非常详细的宣言。是否可以仅将分析器用作工具,还是我真的必须了解整个事物是如何设计的?
编辑: 像这样的教程:
Gmail 内存泄漏修复
使用开发工具
据我所见,它们代表了一些更强的材料。然而,除了介绍 3 Snapshot Technique 的概念之外,我发现它们在实践知识方面提供的很少(对于像我这样的初学者)。’使用 DevTools’ 教程没有通过一个真实的例子来工作,所以它对事物的模糊和一般的概念描述并没有太大的帮助。至于“Gmail”示例:
所以你发现了一个漏洞。 怎么办? 在 Profiles 面板的下半部分检查泄漏对象的保留路径 如果不能轻易推断分配站点(即事件侦听器): 通过 JS 控制台检测保留对象的构造函数以保存分配的堆栈跟踪 使用闭包?启用适当的现有标志(即 goog.events.Listener.ENABLE_MONITORING)以在构造期间设置 creationStack 属性
所以你发现了一个漏洞。 怎么办?
在 Profiles 面板的下半部分检查泄漏对象的保留路径
如果不能轻易推断分配站点(即事件侦听器):
通过 JS 控制台检测保留对象的构造函数以保存分配的堆栈跟踪
使用闭包?启用适当的现有标志(即 goog.events.Listener.ENABLE_MONITORING)以在构造期间设置 creationStack 属性
读完之后,我发现自己更加困惑,而不是更少。再说一次,它只是告诉我 做事 ,而不是告诉我 如何 去做。从我的角度来看,那里的所有信息要么太模糊,要么只对已经了解该过程的人有意义。
查找内存泄漏的一个很好的工作流程是 三个快照 技术,Loreena Lee 和 Gmail 团队首先使用它来解决他们的一些内存问题。步骤一般是:
对于您的示例,我已调整代码以显示此过程(您可以在此处找到它)将主干视图的创建延迟到“开始”按钮的单击事件。现在:
现在您已准备好查找内存泄漏!
您会注意到几种不同颜色的节点。红色节点没有来自 Javascript 的直接引用,但它们是活动的,因为它们是分离的 DOM 树的一部分。树中可能有一个从 Javascript 引用的节点(可能作为闭包或变量),但巧合的是,它阻止了整个 DOM 树被垃圾收集。
然而,黄色节点确实有来自 Javascript 的直接引用。在同一个分离的 DOM 树中查找黄色节点以从您的 Javascript 中定位引用。应该有一个从 DOM 窗口到元素的属性链。
在您的特定页面中,您可以看到标记为红色的 HTML Div 元素。如果您展开该元素,您将看到它被“缓存”函数引用。
选择该行并在您的控制台中输入 $0,您将看到实际的功能和位置:
>$0 function cache( key, value ) { // Use (key + " ") to avoid collision with native prototype properties (see Issue #157) if ( keys.push( key += " " ) > Expr.cacheLength ) { // Only keep the most recent entries delete cache[ keys.shift() ]; } return (cache[ key ] = value); } jquery-2.0.2.js:1166
这是您的元素被引用的地方。不幸的是,您无能为力,它是 jQuery 的内部机制。但是,仅出于测试目的,请执行该功能并将方法更改为:
function cache( key, value ) { return value; }
现在,如果您重复该过程,您将看不到任何红色节点 :)
文档: