web-dev-qa-db-ja.com

Javascriptのメモリリーク:切り離されたDOMツリー

フォームを表示しているときにブラウザのメモリが増加し始めていることに気付きました(これはタスクマネージャから確認できます)。 IE 9の場合、これはいくつかの使用後に500MBを簡単に超えますが、chromeの方が弾力性があります(同じテストを使用すると200MBになります)。

chrome開発者ツールを使用してこの問題をデバッグしています。分離したDOMツリーが多数あることに気づきました:

detached dom tree screenshot

これにより、メモリリークがあることが確認できます。それは正しいでしょうか?次に、問題の根本的な原因を特定する方法を見つける必要があります。保持ツリーを使用して、これらのアイテムの再利用を妨げているものを特定する必要があることを知っています。しかし、保持ツリーの使い方がわかりません。たとえば、上のスクリーンショットの保持ツリーはどういう意味ですか?

どんな援助もいただければ幸いです。

33
Joseph Caruana

DOM要素を参照するコードを作成するときは、留意すべき多くの考慮事項があります。しかし、すべては基本的にいくつかの単純なポイントに要約されます-

a。ローカル関数内で常に参照をクリアします

_var menu = $('body #menu');
// do something with menu
 .
 .
 .
 menu = null;
_

b。要素データの一部として参照を保存しない.data()

c。クロージャー/インラインハンドラー内でDOM参照を使用しないようにし、代わりに識別子を渡す

_    function attachClick(){
      var someDiv = $('#someDiv');

      someDiv.click(function(){
         var a = someDiv....;
         //Wrong. Instead of doing this..
      });


      someDiv.click(function(){
         var a = $('#someDiv');
         //Pass the identifier/selector and then use it to find the element
      });       


      var myFunc = function(){
         var a = someDiv;
         //using a variable from outside scope here - big DON'T!             
      }
    }
_

はい、要素を検索するとページの速度が低下する可能性があると主張できますが、巨大なヒープがespを引き起こすパフォーマンスヒットと比較すると、遅延はごくわずかです。大規模な単一ページアプリケーション。したがって、#3は長所と短所を比較検討した後にのみ使用する必要があります。 (私の場合、それはかなり役に立ちました)

[〜#〜]更新[〜#〜]

d。匿名関数を回避する-イベントハンドラーとローカル関数に名前を付けると、ヒープスナップショットをプロファイリング/確認する際に非常に役立ちます。

27
Robin Maben

コードが多くのDOMサブツリーを作成し、JavaScriptからの参照を保持しているようです。分離したdomツリーから要素を選択する必要があります。スナップショットに従って、テキスト要素を選択する必要があります。そして、リテーナツリーを調べます。

このツリーには、オブジェクトを存続させるすべてのパスが表示されます。少なくとも1つのパス(通常は最短のパス)を使用すると、ウィンドウオブジェクトに移動します。コードに精通している場合は、そのパスで削除する必要があるオブジェクトを簡単に見つけることができますが、そうではありません。パスにはそのようなオブジェクトが多数存在する可能性があります。距離が最も短いオブジェクトのほうが面白いです。

2
loislo