javascript - 使用 Chrome 查找 JavaScript 内存泄漏

标签 javascript google-chrome backbone.js memory-leaks

我创建了一个非常简单的测试用例,它创建了一个 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 的分析器来验证事实是否如此。堆分析器快照上显示了无数的东西,我不知道如何解码好/坏。到目前为止,我看到的教程要么只是告诉我“使用快照分析器”,要么给我一个关于整个分析器如何工作的非常详细的声明。是否可以仅将分析器用作工具,还是我真的必须了解整个事物是如何设计的?

编辑: 像这样的教程:

Gmail memory leak fixing

Using DevTools

根据我所见,代表了一些更强大的 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 树被垃圾收集。

enter image description here

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

在您的特定页面中,您可以看到标记为红色的 HTML Div 元素。如果您展开该元素,您将看到它被“缓存”函数引用。

enter image description here

选择该行并在您的控制台中输入 $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/

相关文章:

javascript - 动态改变 Backbone 模型

javascript - 中止访问 Backbone 模型中的成功回调

javascript - 在 JavaScript 中使用 xpath 恢复 DOM 范围

c# - 在 php 或 JS 中解压缩 SharpZipLib 字符串?

javascript - Chrome 上的 Firebug Lite 导致页脚问题,有解决办法吗?

javascript - 在 Mac 上将 Web 应用程序转换为全屏桌面应用程序?

javascript - 查找值并从深度嵌套的对象数组中删除与该数组关联的整个对象

javascript - 从按键下拉列表中选择值

jquery - 如何在 Chrome 中 console.log jQuery DOM 元素?

backbone.js - 使用 fabric.Image.fromURL 加载 base64 图像