使用Chrome查找JavaScript内存泄漏

我创build了一个非常简单的testing用例,创build一个Backbone视图,将一个处理程序附加到一个事件,并实例化一个用户定义的类。 我相信通过单击此示例中的“删除”button,一切都将被清除,应该没有内存泄漏。

代码的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的分析器来validation这是事实。 堆分析器快照中显示了一大堆事情,我不知道如何解码好坏。 到目前为止,我看到的教程要么告诉我“使用快照分析器”,要么给我一个关于整个分析器工作原理的非常详细的说明。 是否有可能只使用探查器作为工具,或者我真的需要了解整个事情是如何devise的?

编辑:像这样的教程:

Gmail内存泄漏修复

使用DevTools

从我所看到的那里,代表了一些更强大的材料。 然而,除了介绍快照技术的概念外,我发现他们在实践知识(对于像我这样的初学者)方面提供的很less。 “使用DevTools”教程没有通过一个真实的例子,所以它对事物的模糊和一般的概念性描述不是太有帮助。 至于“Gmail”的例子:

所以你发现了一个泄漏。 怎么办?

  • 检查“configuration”面板下半部分泄漏物体的保留path

  • 如果分配站点不能被轻易推断(即事件监听器):

  • 通过JS控制台监视保留对象的构造函数,以保存用于分配的堆栈跟踪

  • 使用闭包? 启用适当的现有标志(即goog.events.Listener.ENABLE_MONITORING)在施工期间设置creationStack属性

阅读后我发现自己更加困惑,而不是更less。 而且,这只是告诉我要做 ,而不是如何去做。 从我的angular度来看,所有的信息要么太模糊,要么只有对已经了解过程的人有意义。

下面@Jonathan Naguin的回答中提出了一些更具体的问题。

查找内存泄漏的良好工作stream程是三种快照技术,Loreena Lee和Gmail团队首先使用这种技术来解决内存问题。 一般的步骤是:

  • 采取堆快照。
  • 做东西。
  • 拿另一个堆快照。
  • 重复相同的东西。
  • 拿另一个堆快照。
  • 在快照3的“摘要”视图中筛选在快照1和快照2之间分配的对象。

对于你的例子,我已经调整了代码来显示这个过程(你可以在这里find它),延迟Backbone View的创build,直到Startbutton的click事件。 现在:

  • 运行HTML(使用此地址在本地保存)并拍摄快照。
  • 点击开始创build视图。
  • 再拍一张快照。
  • 点击删除。
  • 再拍一张快照。
  • 在快照3的“摘要”视图中筛选在快照1和快照2之间分配的对象。

现在你已经准备好find内存泄漏了!

你会注意到一些不同颜色的节点。 红色节点没有从Javascript直接引用它们,但是它们是分离的DOM树的一部分。 从Javascript引用的树中可能有一个节点(可能是一个闭包或variables),但巧合地阻止了整个DOM树被垃圾收集。

在这里输入图像说明

但是,黄色节点确实有直接的Javascript引用。 在同一个分离的DOM树中查找黄色节点以查找来自您的Javascript的引用。 应该有从DOM窗口到元素的一系列属性。

在你的特定的,你可以看到一个标记为红色的HTML Div元素。 如果展开元素,则会看到由“caching”函数引用的元素。

在这里输入图像说明

select行并在您的控制台input$ 0,您将看到实际的function和位置:

 >$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的内部机制。 但是,只是为了testing目的,去function和改变方法:

 function cache( key, value ) { return value; } 

现在,如果你重复这个过程,你将看不到任何红色的节点:)

文档:

  • 消除Gmail中的内存泄漏 。
  • 在Chrome DevTools中简化JavaScript内存分析 。

下面是关于jsfiddle的内存分析技巧:使用下面的URL来隔离你的jsfiddle结果,它将删除所有的jsfiddle框架并只加载你的结果。

http://jsfiddle.net/4QhR2/show/

我从来没有能够找出如何使用时间轴和分析器来追踪内存泄漏,直到我阅读以下文档。 阅读标题为“对象分配跟踪器”的部分后,我可以使用“logging堆分配”工具,并跟踪一些分离的DOM节点。

我通过从jQuery事件绑定切换到使用Backbone事件委托来解决问题。 我的理解是,如果您调用View.remove() ,Backbone的新版本将自动解除绑定事件。 执行一些演示你自己,他们设置与内存泄漏,以供您识别。 如果在学习本文档后仍然没有得到答案,请随时提问。

https://developers.google.com/chrome-developer-tools/docs/javascript-memory-profiling

基本上你需要看看你的堆快照中的对象的数量。 如果两个快照之间的对象数量增加,并且已经处理了对象,则说明存在内存泄漏。 我的build议是在代码中查找不会被分离的事件处理程序。

你也可能想阅读:

http://addyosmani.com/blog/taming-the-unicorn-easing-javascript-memory-profiling-in-devtools/

它解释了chrome开发人员工具的用法,并提供了一些关于如何使用堆快照比较和可用的不同hep快照视图来确认和定位内存泄漏的分步build议。

有一个来自Google的介绍video,这对于发现JavaScript内存泄漏非常有帮助。

https://www.youtube.com/watch?v=L3ugr9BJqIs

您也可以查看开发人员工具中的“时间轴”选项卡。 logging您的应用程序的使用情况,并留意DOM节点和事件监听器的数量。

如果内存图确实会指示内存泄漏,那么可以使用分析器来确定泄漏的内容。

我第二次build议采取堆快照,他们非常适合检测内存泄漏,铬做快照的一个很好的工作。

在我的学位研究项目中,我构build了一个交互式Web应用程序,它必须生成大量的“图层”数据,这些图层中的很多会在UI中“删除”,但由于某些原因,内存不是被释放,使用快照工具我能够确定JQuery一直保持对象的参考(源是当我试图触发一个.load()事件保持参考,尽pipe超出了范围)。 掌握了这些信息后,一手保存了我的项目,当您使用其他人的图书馆时,这是一个非常有用的工具,并且存在这个引发GC停滞不前的问题。

编辑:提前计划要执行哪些操作以最大限度地减less快照时间,假设可能导致问题的原因以及testing每个scheme,在前后创build快照也很有用。