简体   繁体   English

"在 Chrome 开发工具中查找 JS 内存泄漏"

[英]Finding JS memory leak in chrome dev tools

I'm using the chrome dev tools to work out if there is a memory leak in some JS code.我正在使用 chrome 开发工具来确定某些 JS 代码中是否存在内存泄漏。 The memory timeline looks good with memory being reclaimed as expected.内存时间线看起来不错,内存按预期回收。

在此处输入图像描述

However, the memory snapshot is confusing because it appears like there is a leak because there are entries under “Detached DOM Tree”.但是,内存快照令人困惑,因为“分离的 DOM 树”下存在条目,因此看起来好像存在泄漏。

Is the stuff under “Detached DOM Tree” just waiting to be garbage collected or are these real leaks? “分离的 DOM 树”下的东西是等待垃圾收集还是这些真正的泄漏?

Also does anyone know how to find out what function is holding on to a reference to a detached element?还有人知道如何找出对分离元素的引用是什么函数吗?

在此处输入图像描述

Those elements are being referenced in your code but they are disconnected from the page's main DOM tree.这些元素在您的代码中被引用,但它们与页面的主 DOM 树断开连接。

Simple example:简单的例子:

var a = document.createElement("div");

a references a disconnected element now, it cannot be GC'd when a is still in scope. a现在引用了一个断开连接的元素,当a仍在范围内时,它不能被 GC'd。

If the detached dom trees persist in memory then you are keeping references to them.如果分离的 dom 树在内存中持续存在,那么您将保留对它们的引用。 It is somewhat easy with jQuery to do this, just save a reference to a traversed result and keep that around.使用 jQuery 做到这一点有点容易,只需保存对遍历结果的引用并保留它。 For example:例如:

var parents = $("span").parent("div");
$("span").remove();

Now the spans are referenced even though it doesn't appear you are referencing them anyhow.现在跨度被引用,即使看起来你无论如何都没有引用它们。 parents indirectly keeps references to all the spans through the jQuery .prevObject property. parents通过 jQuery .prevObject属性间接保持对所有跨度的引用。 So doing parents.prevObject would give the object that references all the spans.所以做parents.prevObject会给出引用所有跨度的对象。

See example here http://jsfiddle.net/C5xCR/6/ .请参阅此处的示例http://jsfiddle.net/C5xCR/6/ Even though it doesn't directly appear that the spans would be referenced, they are in fact referenced by the parents global variable and you can see the 1000 spans in the Detached DOM tree never go away.尽管没有直接显示跨度会被引用,但它们实际上是由parents全局变量引用的,您可以看到分离的 DOM 树中的 1000 个跨度永远不会消失。

Now here's the same jsfiddle but with:现在这是相同的 jsfiddle,但具有:

delete parents.prevObject

And you can see the spans are no longer in the detached dom tree, or anywhere for that matter.你可以看到跨度不再在分离的 dom 树中,或者任何地方。 http://jsfiddle.net/C5xCR/7/ http://jsfiddle.net/C5xCR/7/

Is the stuff under “Detached DOM Tree” just waiting to be garbage collected or are these real leaks? “分离的 DOM 树”下的东西是等待垃圾收集还是这些真正的泄漏?

Before taking snapshot the browser will run garbage collection and sweep all objects that are not referenced.在拍摄快照之前,浏览器将运行垃圾收集并清除所有未引用的对象。 So the heap snapshot always contain only live objects.所以堆快照总是只包含活动对象。 As a consequence if a Detached DOM Tree is in the snapshot than there must be an element in the tree that is referenced from JavaScript.因此,如果快照中存在分离的 DOM 树,则树中必须有一个从 JavaScript 引用的元素。

Also does anyone know how to find out what function is holding on to a reference to a detached element?还有人知道如何找出对分离元素的引用是什么函数吗?

There should be an element(or several of them) in the same detached DOM tree that has yellow background.在同一个分离的 DOM 树中应该有一个元素(或其中几个)具有黄色背景。 Such elements are referenced from the JavaScript code.这些元素是从 JavaScript 代码中引用的。 You can find out who exactly keeps reference to the element in the retainers tree.您可以找出谁确切地保留了对保留树中元素的引用。

Since you've added the jQuery tag, I had a sneaky suspicion as to this being a jQuery thing .既然你已经添加了 jQuery 标签,我就偷偷地怀疑这是一个 jQuery的东西 A quick google brought me to this page .一个快速的谷歌把我带到了这个页面 When using jQ's detach method, a reference to the object is still kept in memory, so that could be causing your snapshot.当使用 jQ 的detach方法时,对对象的引用仍保存在内存中,因此可能会导致您的快照。

Another thing could be that jQuery has a div node at hand, which is -obviously- kept in memory, but never added to the actual dom... a sort of document.createNode('div') without appending it.另一件事可能是 jQuery 手头有一个div节点,它 - 显然 - 保存在内存中,但从未添加到实际的 dom 中......一种document.createNode('div')没有附加它。 This, too, will show up in the memory snapshot.这也将显示在内存快照中。 You can't get around this, jQuery uses it to parse strings into html elements.你无法解决这个问题,jQuery 使用它将字符串解析为 html 元素。

So to remove some elements from memory, use the jQuery .remove() method, and your mem will be cleared instantly .因此,要从内存中删除一些元素, 请使用 jQuery .remove()方法,您的内存将立即被清除 cf Esailija's comment on why remove doesn't quite fit the bill here . cf Esailija 关于为什么remove不完全符合这里的要求的评论
$('#someElem')[0].parentNode.removeChild($('#someElem')[0]); Should remove the element altogether, but might not unbind the events.应该完全删除元素,但可能不会取消绑定事件。 Perhaps something along the lines of:也许是这样的:

$('#someElem').detach();//to remove any event listeners
$('#someElem')[0].parentNode.removeChild($('#someElem')[0]);//remove element all together

And, again, as Esailija pointed out in his answer, make sure that you assign references to any jQuery object ( var someRef= $('.someSelector'); ) to a global variable, as they won't be GC'ed.而且,正如 Esailija 在他的回答中指出的那样,确保将对任何 jQuery 对象( var someRef= $('.someSelector'); )的引用分配给全局变量,因为它们不会被 GC 处理。 Just avoid globals all together, in fact.事实上,只要避免全局变量。
But to answer your question briefly, and clearly: no these aren't real memory leaks, the memory should be freed on the onbeforeunload event.但是要简短而清楚地回答您的问题:不,这些不是真正的内存泄漏,应该在onbeforeunload事件上释放内存。 The jQuery object is deleted, so all references go out of scope. jQuery 对象被删除,因此所有引用都超出了范围。 At least, That's what my "research" lead me to believe.至少,这就是我的“研究”让我相信的。 Perhaps not entirely relevant, but just as a reference Here's a question on mem-leaks I posted a while back, and with it a few things I found out.. 也许不完全相关,但只是作为参考这是我不久前发布的关于 mem-leaks 的问题,并通过它发现了一些事情..

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM