2012-04-10 6 views
10

jQuery.dataと生の展開プロパティ(DOMノードに割り当てることのできる任意の属性)の宣伝されている利点の1つは、jQuery.dataが「循環参照から安全であり、メモリリークがない」ということです。 WebアプリケーションのためのJavaScriptの正確な説明<-> DOM循環参照の問題

最も一般的なメモリリークがJavaScriptのスクリプトエンジンとブラウザのC++ オブジェクトのJavaScriptの間で例えば(DOMの実装間の循環 参照を伴う:"Optimizing JavaScript code"題しGoogleからの記事では、より多くの詳細に立ち入りスクリプト エンジンとInternet ExplorerのCOMインフラストラクチャ、または JavaScriptエンジンとFirefox XPCOMインフラストラクチャの間)。 Expando →中間オブジェクト→ DOM要素

介し

  • DOM要素→イベントハンドラ→閉鎖スコープ→ DOM

  • DOMエレメント→:

それは円形の基準パターンの2つの例を示します

しかし、DOMノードとJavaScriptオブジェクトの間の参照サイクルでメモリリークが発生した場合、これは自明ではないイベントハンドラ(例: onclick)はこのようなリークを生成するでしょうか?

  • DOM要素はイベントハンドラを参照しています。私はそれを見る方法ので、私は、それが基準サイクルを避けるために、イベントハンドラのためにも、可能ですか表示されません。

  • イベントハンドラは、(直接的または間接的に)DOMを参照します。どんな場合でも、windowを興味深いイベントハンドラで参照することを避けることは、ほとんどありません。setIntervalループを書き込んで、グローバルキューからアクションを読み込むのは簡単ではありません。

JavaScript ↔ DOM循環参照問題の詳細な説明はありますか?私が明確にしたいもの:

  • どのブラウザが影響を受けますか? jQueryソースのコメントには特にIE6-7が含まれていますが、Googleの記事によるとFirefoxにも影響があることが示唆されています。

  • expandoプロパティとイベントハンドラは、メモリリークに関してどういう違いがありますか?または、これらのコードスニペットの両方が、同じ種類のメモリリークの影響を受けやすいのですか?

    // Create an expando that references to its own element. 
    var elem = document.getElementById('foo'); 
    elem.myself = elem; 
    
    // Create an event handler that references its own element. 
    var elem = document.getElementById('foo'); 
    elem.onclick = function() { 
        elem.style.display = 'none'; 
    }; 
    
  • ページが原因循環参照に、メモリリークが発生した場合、全体のブラウザアプリケーションが閉じている、またはウィンドウ/タブが閉じられたときに、メモリが解放されるまで、漏れが持続しますか?

+1

このコードは実際にメモリリークを引き起こしますか?私はなぜなのか理解していない。 var elem = document.getElementById( 'foo'); elem.myself = elem; – CEGRD

答えて

5

これはおそらく、これらのリンク内のすべてのコンテンツを再生する価値はないので、私はあなたには、いくつかの読書やother Google search hitsを見て行うことをお勧めしたい:

javascript, circular references and memory leaks

Do you know what may cause memory leaks in JavaScript?

http://www.ibm.com/developerworks/web/library/wa-memleak/

http://www.ibm.com/developerworks/web/library/wa-sieve/index.html?ca=drs-

http://code.google.com/p/google-web-toolkit/wiki/UnderstandingMemoryLeaks

最悪のメモリリークは、リークが(あなたが影響を受けるWebページを離れた後も)永続的IE6です。他のリークは一般的にあなたがその特定のページにいる間のみ、ページを出るときにクリーンアップされます。

実際、ブラウザは循環参照を処理できるはずです。 DOM要素がまだJavaScript要素によって参照されているにもかかわらず、JavaScript要素自体が存在するのは、DOM要素がまだ生きているためにDOM要素に残っている真の外部参照がないためです。これは、IEの古いバージョンが悪かったという認識です。したがって、イベントハンドラを含むコード参照では、ガベージコレクタは、JavaScriptのDOM要素に残っている唯一の参照が、DOM要素とそのイベントハンドラが削除されたときに消える参照であることを知るには十分スマートである必要があります。真の外部参照がないので、DOM要素とイベントハンドラの両方を削除することは安全です。これは、オブジェクトAがオブジェクトBを参照し、オブジェクトBがオブジェクトAを参照しているが、他のオブジェクトがAまたはBのいずれも参照していないので、両方の解放が可能な一般的な循環参照問題のより複雑なバージョンです。

jQueryの.data()は、以前のバージョンのIEではDOM要素に追加されたプロパティに特有の問題があったため、循環参照が正しく処理されないため、 (漏れ)があるはずです。 .data()は、安全で漏れのない文字列であるDOM要素に1つの追加されたプロパティのみを使用することで、この問題を回避します。その文字列は、DOM要素と関連付けるすべてのプロパティを含むJavaScriptオブジェクトのキーです。これらのプロパティはすべてブラウザに循環参照バグがない単純なJavaScriptに格納されているため、このようにしてもリークは発生しません。

まだ循環参照がいくつかあるかもしれないことを理解することが重要です。これは問題ありません。回避策は、循環参照を、ブラウザがバグを持つ場所に置くのではなく、ブラウザを適切に処理する場所に移動することです。

+0

IE6-7では、expandoプロパティ(これは '.data'が動きます)のためにDOMとJS間の循環参照を適切にガベージコレクションしません。イベントハンドラの参照を適切にガベージコレクションするかどうか –

+0

@joeyadams - そうだと思います。 – jfriend00