8

AngularJS アプリのメモリ リークの解決策を見つけようとしています。私は AngularJS の世界に慣れていないので、どこから始めて、どこを修正してコードを最適化すればよいのかよくわかりません。

最初にアプリケーションの簡単な説明をしようと思います。その後、測定可能なメモリ統計をいくつか投稿します。使用メモリを測定するために、3 つの診断ツールを使用しました。Windows (7) タスク マネージャ、Firefox about:memory、および Firefox 拡張機能 MemChaser です。

応用

  • アプリケーションはページに埋め込まれており、一度読み込まれ、少なくとも 24 時間そこにとどまる必要があります
  • データは$http() Ajax リクエストを介して 1 ~ 60 分間隔で継続的にロードされます
  • データは、何らかの階層構造を持つ JSON オブジェクトです
  • この階層のすべてのレイヤーには、カスタム コンポーネントがあります (分離されたスコープを持つ)。
  • データの選択された部分が認識され、Ajax リクエストを超えて保持されます
  • ほとんどのディレクティブは、HTML ファイルを ( $http()経由で) ロードして、テンプレートとしてコンパイルします。

統計学

  • ウィンドウズタスクマネージャー

    Firefox が使用するメモリは、1 時間あたり 50 ~ 100 MB 増加します。

  • 概要:メモリ

                                       Size (MB)   20 min diff  Size (MB)
    JS-Main-Runtime                     32         36/+113%      68
    JS-Main-Runtime-GC-Heap-Committed   20         27/+135%      47
    Heap-Allocated                      54         29/+54%       83
    Heap-Committed                      63         28/+44%       91
    JS-GC-Heap                          31         26/+84%       57
    Private                            156         58/+37%      214
    Resident                           175         62/+35%      237
    VSize                              509         86/+17%      595
    
  • MemChaser 0.5.2.1

                   12:17   12:27   12:57   13:17
    Resident (MB)  140     164     243     270     
    iGC (ms)        42      24      40      42
    CC (ms)          3      53     206     286
    

    Resident : 物理メモリに存在するプロセスによって使用されるメモリ。 iGC : 最後のガベージ コレクター アクティビティの期間。 CC : 最後のサイクル コレクター アクティビティの期間。

これらの結果はかなり劇的で、サイクル コレクターが最良のヒントを与えてくれるようです。ビュー (Ajax リクエストのみ) なしでアプリを実行しても、劇的なことは何も起こりません。動的テンプレートの読み込みを無効にすると、動的テンプレートを使用したバージョンとの明確な違いはありません。したがって、これら 2 つのトピックが原因ではないようです。

私の考え: すべての Ajax リクエストで、新しいスコープと DOM ノードが作成されます。DOM ノードは後で削除される可能性がありますが、そこにあるデータを含むスコープはメモリ内に残っている可能性があります。それは考えられるシナリオであり、メモリリークの原因ですか?

AngularJS のディレクティブ、スコープ、およびバインディングを適切に操作して、このようなメモリ リークを回避するにはどうすればよいでしょうか?

どんな助けでもとても嬉しいです。

トバイアス

4

1 に答える 1

3

この種の問題のデバッグを支援するために、 AngularJS Batarang Chrome 拡張機能を使用します。この拡張機能の [モデル] タブと [パフォーマンス] タブを監視して、ダングリングまたはリークしているスコープを見つけます。特定のスコープが不要になったときに$destroyを実行してください。たとえば、 ngRepeat がこれを行う方法を参照してください。

ドキュメントから:

$destroy()

親スコープから現在のスコープ (およびそのすべての子) を削除します。削除は、$digest() への呼び出しが現在のスコープとその子に伝播されなくなることを意味します。削除は、現在のスコープがガベージ コレクションの対象であることも意味します。

$destroy() は通常、ループの展開を管理するために ngRepeat などのディレクティブによって使用されます。スコープが破棄される直前に、このスコープで $destroy イベントがブロードキャストされます。
アプリケーション コードは、必要なクリーンアップを実行する機会を与える $destroy イベント ハンドラーを登録できます。AngularJS には、要素が DOM から削除される前に DOM バインディングをクリーンアップするために使用できる $destroy jQuery イベントもあることに注意してください。

$destroy() は、スコープとその子スコープを親から完全に切り離し、呼び出しによるモデル変更の検出とリスナー通知への参加を停止する必要がある場合に、スコープで呼び出す必要があります。

于 2013-10-30T13:30:50.760 に答える