使用Chrome查找JavaScript内存泄漏

2020/10/27 22:42 · javascript ·  · 0评论

我创建了一个非常简单的测试用例,该用例创建了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();

但是,我不清楚如何使用Google Chrome浏览器的探查器来验证是否确实如此。堆探查器快照中显示了无数个庞大的信息,而且我不知道如何解码优缺点。到目前为止,我看过的教程只是告诉我“使用快照事件探查器”,或者为我提供了有关整个事件探查器如何工作的非常详细的清单。可以仅将探查器用作工具,还是我真的必须了解整个项目是如何设计的?

编辑:像这样的教程:

Gmail内存泄漏修复

使用DevTools

从我所见,可以代表一些更强大的材料。但是,除了介绍3快照技术的概念外,我发现它们对实践知识的提供很少(对于像我这样的初学者)。“使用DevTools”教程无法通过一个真实的示例进行工作,因此它对事物的含糊和笼统的概念描述并不太有用。至于“ Gmail”示例:

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

  • 检查“轮廓”面板下半部分中泄漏物体的固定路径

  • 如果无法轻易推断出分配站点(即事件侦听器):

  • 通过JS控制台检测保留对象的构造函数,以保存堆栈跟踪以进行分配

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

阅读后,我发现自己更加困惑,而不是更少。再说一次,这只是告诉我去做事情,而不是如何去做。从我的角度来看,那里的所有信息要么太含糊,要么只对已经了解该过程的人有意义。

以下@Jonathan Naguin的答案提出了其中一些更具体的问题

A good workflow to find memory leaks is the three snapshot technique, first used by Loreena Lee and the Gmail team to solve some of their memory problems. The steps are, in general:

  • Take a heap snapshot.
  • Do stuff.
  • Take another heap snapshot.
  • Repeat the same stuff.
  • Take another heap snapshot.
  • Filter objects allocated between Snapshots 1 and 2 in Snapshot 3's "Summary" view.

For your example, I have adapted the code to show this process (you can find it here) delaying the creation of the Backbone View until the click event of the Start button. Now:

  • Run the HTML (saved locally of using this address) and take a snapshot.
  • Click Start to create the view.
  • Take another snapshot.
  • Click remove.
  • Take another snapshot.
  • Filter objects allocated between Snapshots 1 and 2 in Snapshot 3's "Summary" view.

Now you are ready to find memory leaks!

您会注意到一些不同颜色的节点。红色节点没有从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;
}

现在,如果您重复此过程,您将看不到任何红色节点:)

说明文件:

这是有关jsfiddle内存分析的提示:使用以下URL隔离jsfiddle结果,它将删除所有jsfiddle框架并仅加载结果。

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

在阅读以下文档之前,我始终无法弄清楚如何使用时间轴和事件探查器来跟踪内存泄漏。阅读了标题为“对象分配跟踪器”的部分后,我可以使用“记录堆分配”工具,并跟踪一些独立的DOM节点。

我通过从jQuery事件绑定切换为使用Backbone事件委托来解决了该问题。据我了解,如果您致电,较新版本的Backbone将自动为您取消绑定事件View.remove()自己执行一些演示,它们设置有内存泄漏,供您识别。在学习了本文档之后,如果您仍然不明白,请随时在这里提问。

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

基本上,您需要查看堆快照中的对象数。如果两个快照之间的对象数量增加,并且您已经废弃了对象,则可能会发生内存泄漏。我的建议是在代码中寻找不会分离的事件处理程序。

有一个来自Google的介绍视频,它将对发现JavaScript内存泄漏非常有帮助。

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

您还可以查看开发人员工具中的“时间轴”标签。记录应用程序的使用情况,并注意DOM节点和事件侦听器的数量。

如果内存图确实表明存在内存泄漏,则可以使用探查器找出泄漏的内容。

您可能还需要阅读:

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

它说明了chrome开发人员工具的用法,并提供了有关如何使用堆快照比较和可用的不同堆快照视图来确认和定位内存泄漏的逐步建议。

我第二次建议创建堆快照,它们非常适合检测内存泄漏,chrome可以出色地完成快照。

在我本人的研究项目中,我正在构建一个交互式Web应用程序,该应用程序必须生成在“层”中构建的大量数据,其中许多层将在UI中被“删除”,但由于某种原因,内存并未被删除。被释放后,使用快照工具可以确定JQuery一直在对象上保留引用(源是当我试图触发一个.load()事件时,尽管超出范围但仍保留了该引用)。一手掌握这些信息就可以保存我的项目,当您使用其他人的库时,它是一个非常有用的工具,并且您会遇到挥之不去的引用问题,从而使GC无法完成其工作。

EDIT:
It's also useful to plan ahead what actions you're going to perform to minimize time spent snapshotting, hypothesize what could be causing the problem and test each scenario out, making snapshots before and after.

A couple of important notes in regards to identifying memory leaks using Chrome Developer tools:

1) Chrome itself has memory leaks for certain elements such as password and number fields. https://bugs.chromium.org/p/chromium/issues/detail?id=967438. Avoid using those while debugging as they polute your heap snapshot when searching for detached elements.

2) Avoid logging anything to the browser console. Chrome will not garbage collect objects written to the console, hence affecting your result. You can suppress output by placing the following code in the beginning of you script/page:

console.log = function() {};
console.warn = console.log;
console.error = console.log;

3)使用堆快照并搜索“分离”以标识分离的DOM元素。通过将对象悬停,您可以访问所有属性,包括id and outerHTML which may help identify each element.
JS Heap Snapshot的屏幕快照,其中包含有关分离的DOM元素的详细信息
If the detached elements are still too generic to recognize, assign them unique IDs using the browser console prior to running your test, e.g.:

var divs = document.querySelectorAll("div");
for (var i = 0 ; i < divs.length ; i++)
{
    divs[i].id = divs[i].id || "AutoId_" + i;
}
divs = null; // Free memory

现在,当您使用来标识一个分离的元素时,假设id =“ AutoId_49”,重新加载页面,再次执行上面的代码片段,然后使用DOM inspector或document.querySelector(..)查找id =“ AutoId_49”的元素。 。自然,这仅在您的页面内容可预测时才有效。

我如何运行测试以识别内存泄漏

1)加载页面(抑制控制台输出!)

2)在页面上做可能导致内存泄漏的操作

3)使用开发人员工具拍摄堆快照并搜索“分离”

4)悬停元素以从其idexternalHTML属性中识别它们

本文地址:http://javascript.askforanswer.com/shiyongchromechazhaojavascriptneicunxielou.html
文章标签: ,   ,   ,  
版权声明:本文为原创文章,版权归 javascript 所有,欢迎分享本文,转载请保留出处!

文件下载

老薛主机终身7折优惠码boke112

上一篇:
下一篇:

评论已关闭!