我创建了一个非常简单的测试用例,它创建了一个 Backbone View ,将一个处理程序附加到一个事件,并实例化一个用户定义的类。我相信通过点击这个示例中的“删除”按钮,一切都会被清理干净,应该不会有内存泄漏。
代码的 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();
但是,我不清楚如何使用 Google Chrome 的分析器来验证事实是否如此。堆分析器快照上显示了无数的东西,我不知道如何解码好/坏。到目前为止,我看到的教程要么只是告诉我“使用快照分析器”,要么给我一个关于整个分析器如何工作的非常详细的声明。是否可以仅将分析器用作工具,还是我真的必须了解整个事物是如何设计的?
编辑: 像这样的教程:
根据我所见,代表了一些更强大的 Material 。然而,除了介绍 3 快照技术 的概念之外,我发现它们在实践知识方面提供的很少(对于像我这样的初学者而言)。 '使用 DevTools' 教程没有通过一个真实的例子来工作,所以它对事物的模糊和一般的概念描述并没有太大的帮助。至于“Gmail”示例:
So you found a leak. Now what?
Examine the retaining path of leaked objects in the lower half of the Profiles panel
If the allocation site cannot be easily inferred (i.e. event listeners):
Instrument the constructor of the retaining object via the JS console to save the stack trace for allocations
Using Closure? Enable the appropriate existing flag (i.e. goog.events.Listener.ENABLE_MONITORING) to set the creationStack property during construction
读完之后,我发现自己更加困惑,而不是更少。再说一遍,它只是告诉我做事,而不是如何去做。从我的 Angular 来看,那里的所有信息要么太模糊,要么只对已经了解流程的人有意义。
其中一些更具体的问题已在 @Jonathan Naguin's answer 中提出。下面。
最佳答案
三个快照技术是查找内存泄漏的一个很好的工作流程,Loreena Lee 和 Gmail 团队首先使用它来解决他们的一些内存问题。一般来说,这些步骤是:
- 拍摄堆快照。
- 做事。
- 拍摄另一个堆快照。
- 重复相同的内容。
- 拍摄另一个堆快照。
- 在快照 3 的“摘要” View 中过滤在快照 1 和 2 之间分配的对象。
对于您的示例,我已调整代码以显示此过程(您可以找到它 here),将主干 View 的创建延迟到“开始”按钮的单击事件。现在:
- 运行 HTML(使用此 address 保存在本地)并拍摄快照。
- 点击开始创建 View 。
- 再拍一张快照。
- 点击删除。
- 再拍一张快照。
- 在快照 3 的“摘要” View 中过滤在快照 1 和 2 之间分配的对象。
现在您可以发现内存泄漏了!
您会注意到几种不同颜色的节点。红色节点没有来自 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;
}
现在,如果您重复该过程,您将看不到任何红色节点 :)
文档:
关于javascript - 使用 Chrome 查找 JavaScript 内存泄漏,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/19621074/