42

一部のJSコードにメモリリークがあるかどうかを調べるために、クロム開発ツールを使用しています。メモリ タイムラインは、メモリが期待どおりに再利用されているように見えます。

ここに画像の説明を入力

ただし、「Detached DOM Tree」の下にエントリがあるため、メモリ スナップショットがリークしているように見えてわかりにくいです。

「Detached DOM Tree」の下にあるものは、ガベージ コレクションを待っているだけですか、それとも本当のリークですか?

また、切り離された要素への参照を保持している関数を見つける方法を知っている人はいますか?

ここに画像の説明を入力

4

3 に答える 3

34

これらの要素はコードで参照されていますが、ページのメイン DOM ツリーから切り離されています。

簡単な例:

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

a現在、切断された要素を参照していますa。まだスコープ内にある場合は、GC できません。

デタッチされた dom ツリーがメモリに保持されている場合は、それらへの参照を保持しています。jQuery を使用すると、これを行うのはいくらか簡単です。トラバースされた結果への参照を保存し、それを維持するだけです。例えば:

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

とにかくスパンを参照しているように見えなくても、スパンが参照されるようになりました。jQueryプロパティparentsを介して間接的にすべてのスパンへの参照を保持します。.prevObjectそうparents.prevObjectすることで、すべてのスパンを参照するオブジェクトが得られます。

http://jsfiddle.net/C5xCR/6/の例を参照してください。スパンが直接参照されるようには見えませんが、実際にはparentsグローバル変数によって参照されており、Detached DOM ツリーの 1000 スパンが消えることはありません。

これは同じjsfiddleですが、次のとおりです。

delete parents.prevObject

また、スパンが切り離された dom ツリーやどこにも存在しないことがわかります。http://jsfiddle.net/C5xCR/7/

于 2012-08-13T08:01:49.583 に答える
16

「DetachedDOMTree」の下にあるものは、ガベージコレクションを待っているだけですか、それともこれらの本当のリークですか?

スナップショットを作成する前に、ブラウザはガベージコレクションを実行し、参照されていないすべてのオブジェクトをスイープします。したがって、ヒープスナップショットには常にライブオブジェクトのみが含まれます。結果として、切り離されたDOMツリーがスナップショットにある場合は、JavaScriptから参照される要素がツリーに存在する必要があります。

また、デタッチされた要素への参照を保持している関数を見つける方法を知っている人はいますか?

同じデタッチされたDOMツリーに、背景が黄色の要素(またはそれらのいくつか)が存在する必要があります。このような要素は、JavaScriptコードから参照されます。リテーナツリーの要素を正確に参照しているのは誰かを見つけることができます。

于 2012-08-14T13:15:39.097 に答える
1

あなたが jQuery タグを追加したので、私はこれが jQuery のものであるという卑劣な疑いを持っていました。簡単なグーグルでこのページにたどり着きました。jQ のdetachメソッドを使用する場合、オブジェクトへの参照は引き続きメモリに保持されるため、スナップショットが発生する可能性があります。

もう1つのことは、jQueryがdiv手元にノードを持っている可能性があります。これは明らかにメモリに保持されていますが、実際のdomには追加されていません...一種のdocument.createNode('div')追加なしです。これもメモリ スナップショットに表示されます。これを回避することはできません。jQuery はこれを使用して、文字列を html 要素に解析します。

したがって、メモリからいくつかの要素を削除するには、jQuery.remove()メソッドを使用すると、mem が即座にクリアされますcf Esailja の理由についてのコメントはremove、ここの法案に完全には適合しません
$('#someElem')[0].parentNode.removeChild($('#someElem')[0]);要素を完全に削除する必要がありますが、イベントのバインドを解除しない可能性があります。おそらく、次のようなものです。

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

そして、繰り返しますが、Esailja が彼の回答で指摘したように、jQuery オブジェクトへの参照 ( var someRef= $('.someSelector');) をグローバル変数に割り当てるようにしてください。これらは GC されないためです。実際、グローバルを一緒に避けるだけです。
しかし、あなたの質問に簡潔かつ明確に答えるために: いいえ、これらは実際のメモリ リークではありませんonbeforeunload。イベントでメモリを解放する必要があります。jQuery オブジェクトが削除されるため、すべての参照が範囲外になります。少なくとも、それが私の「研究」が私に信じさせたものです。おそらく完全に関連しているわけではありませんが、参考としてここに私がしばらく前に投稿したmem-leaksに関する質問があります.

于 2012-08-13T08:10:12.177 に答える