23

アプリケーションでメモリ リークはまだ発生していませんが、将来起こりうる問題について心配しています。このようなことをしているかどうか知りたいです:

SomeClass.prototype.someMethod= function() {
    var that= this
    this.$div2.click(function() {
        that.someMethod2();
    });
}

そして、this.$div2 が別の div this.$div1 に追加されたとしましょう。私が電話したら

this.$div1.remove();

後で SomeClass インスタンスの参照を失います SomeClass インスタンスはガベージコレクションされますか? そして、HTML 要素 this.$div2 はどうですか? this.$div2 は this.$div1 に追加されるため、DOM 内にはありません。

これは、this.$div2 のイベント ハンドラーが HTML 要素 this.$div2 への参照を保持し、変数 "that" のためにクロージャーを介して SomeClass のインスタンスへの参照を保持する可能性があるためです。

では、このようにすべてのイベントと HTML 要素を適切に削除する必要がありますか? それとも単に「ルート」要素 (this.$div1) を削除するだけで問題は解決しますか?

4

3 に答える 3

17

this.$div2に追加されthis.$div1ます。呼び出しthis.$div1.remove();て後でインスタンスの参照を失ったSomeClass場合、SomeClassインスタンスはガベージコレクションされますか?

はい、それへのすべての参照が失われると(イベントハンドラーを介した参照も)、インスタンスはガベージコレクションされる可能性があります。

そして、HTML要素はthis.$div2どうですか?this.$div2に追加されるため、DOM内にはありませんthis.$div1

現在DOMに接続されているかどうかは関係ありません。収集できないオブジェクトが参照$div1している場合、その子ノード$div2とそのイベントハンドラーにもアクセスできるため、ハンドラーから参照されているインスタンスは収集できません。

this.$div2のイベントハンドラーがHTML要素への参照を保持し、変数「that」のためにクロージャーthis.$div2を介してのインスタンスへの参照も保持する可能性があるため、これを尋ねます。SomeClass

これは循環参照であり、エンジンによって適切に処理される必要があります(円の内側のオブジェクトが外側から参照されていない場合は、収集できます)。ただし、(古い?)DOMオブジェクトがサークルに含まれている場合、InternetExplorerはこれを実行できません。

そのため、.removejQueryメソッドコード)は、すべてのイベントリスナーを切り離す(内部)cleanDataメソッドを内部的に呼び出します。

したがって、このようなすべてのイベントとHTML要素を適切に削除する必要がありますか?または、単に「ルート」要素(this。$ div1)を削除するだけで問題は解決しますか?

はい、removejQueryラッパーを呼び出すと、すべてのイベント(すべての子要素から)とDOMノードが自動的に削除されます。

于 2012-12-23T20:35:11.643 に答える
7

このように、すべてのイベントと HTML 要素を適切に削除する必要がありますか?

短い答えはノーです!少なくとも 99% のケースでは、1 つの DOM 要素によって使用されるメモリは、Web ページによって使用される全体のメモリに比べて取るに足らないものであるため、まったく問題になりません。

ただし、不要なオブジェクトを破棄して使用したメモリを解放することは常に良い方法ですが、ガベージ コレクションは完全にブラウザ次第であるため、要素によって使用されたメモリを GC が確実に解放するとは言えません。理論的には、GC は DOM 要素への参照がない場合にのみ起動する必要があります。少なくともChrome はそのように動作しますが、JavaScript などの言語では、オブジェクトの処理が完了したことをランタイムに明示的に通知しません。 JavaScript ではすぐに混乱します: 関数はオブジェクトをさらにいくつかの関数に渡す可能性があり、オブジェクトはさらに別のオブジェクト内のメンバーとして保存される可能性があり、オブジェクトはクロージャーなどを介して参照される可能性があるため、完全にブラウザー次第ですそして何を集めるか!

あなたの場合、削除div1するとhtmlドキュメントが解放され、要素はビューにレンダリングされません。実際、jQueryのremoveメソッドは、要素自体とともに要素に添付されたすべてのイベント、expandoプロパティ、および子要素を削除しますが、div1およびdiv2別のオブジェクト内での参照により、両方の DOM 要素が孤児要素になります! インスタンス変数を削除する SomeClassと、DOM 要素へのすべての参照が解放され、ガベージ コレクションの候補になりますが、DOM 要素がclusurethatのインスタンスへの参照を作成するトリッキーな変数が登場します! SomeClassこの問題はCircular Reference、IE では次のように知られています。

相互参照を格納する JavaScript オブジェクトと DOM 要素が原因で、Internet Explorer のガベージ コレクターがメモリを回収せず、メモリ リークが発生する

ここに画像の説明を入力

詳細については、こちらをご覧ください。

この特定のリークは、主に IE<8 の歴史的関心事ですが、循環リンクを壊す良い例は、変数の使用を避けthat、代わりにプロキシまたはデリゲートを使用して、イベント ハンドラーのコンテキストを特定のコンテキストに変更することです。

ECMA の 5 番目のバインド メソッドは、DOM イベント ハンドラーに関してコンテキストを変更するのに便利です。変数クロージャーを使用しないコードに基づく単純なハンドラーを次に示します。

this.$div2.click((function() {
        this.someMethod2();
    }).bind(this));
于 2012-12-23T20:52:09.347 に答える
1

要素を動的に作成する場合は、それらにイベントを割り当てます。私はあなたのコードがそれをする良い方法ではないと思います。次の方法に従う必要があります。

固定要素の場合、イベントが必要な場合は、これら2つの関数を使用してください。最初はコンストラクタで呼び出され、2番目はデストラクタで呼び出されます。

on_Events: function() {
   $('your_form').on('event_name', {element_Selector}, callback_function)
},
off_Events: function() {
   $('your_form').off('event_name', {element_Selector}, callback_function)
}

動的オブジェクト用。要素を作成するときにイベントを追加し、要素を破棄する直前にこれらのイベントを削除します。

于 2012-12-25T01:49:07.803 に答える