デタッチされた要素ツールを使用して DOM メモリ リークをデバッグする

Detached Elements ツールを使用して、ブラウザーでガベージ コレクションできないデタッチされた要素を見つけ、デタッチされた要素をまだ参照している JavaScript オブジェクトを見つけます。 JavaScript を変更して要素を解放することで、ページ上のデタッチされた要素の数を減らすことができます。

メモリ リークは、要素がドキュメント オブジェクト モデル (DOM) ツリーにアタッチされなくなったが、ページ上で実行されている一部の JavaScript によって引き続き参照されている場合に、アプリケーションで発生する可能性があります。 これらの要素はデタッチ された要素と呼ばれます。 ブラウザーがデタッチされた要素をガベージ コレクション (GC) するには、DOM ツリーまたは JavaScript コードから要素を参照することはできません。

ヒープ スナップショットとデタッチされた要素の詳細については、「ヒープ スナップショットを使用 してデタッチされた DOM ツリー メモリ リークを検出する」を参照してください。

「メモリの問題の修正」で説明されているように、メモリの問題は、メモリ リーク、メモリの膨らみ、頻繁なガベージ コレクションなど、ページのパフォーマンスに影響します。 ユーザーの症状は次のとおりです。

  • ページのパフォーマンスは、時間の経過と同時に徐々に悪化します。
  • ページのパフォーマンスは一貫して悪いです。
  • ページのパフォーマンスが遅れているか、頻繁に一時停止しているように見えます。

デタッチされた要素ツールを開く

デタッチされた要素ツールを開き、デモ ページを読み込むには:

  1. デタッチされた要素のデモ アプリケーションを新しいウィンドウまたはタブで開きます。

  2. DevTools を開くには、Web ページを右クリックし、[ 検査] を選択します。 または、 Ctrl + Shift + I (Windows、Linux) または Command + Option + I (macOS) を押します。 DevTools が開きます。

  3. DevTools の アクティビティ バーで、[ デタッチされた要素 ] タブを選択します。そのタブが表示されない場合は、[ その他のツール ] ([その他のツール] アイコン) ボタンをクリックします。

    デタッチされた要素ツールを開く

デタッチされた要素を取得する

デタッチされた要素の取得ツールの [デタッチされた要素の取得] ([デタッチされた要素の取得] アイコン) ボタンは、切断されたすべての要素を Web ページで検索して表示します。

デタッチされた要素を検索するには:

  1. デモ アプリケーションで、[ 会議室 1 ] ボタンが選択されていることを確認します。

  2. デモ アプリケーションで、[ 高速トラフィック ] ボタンをクリックします。

  3. 一部のメッセージが生成され、デモ アプリケーションに表示されたら、デモの [停止 ] ボタンをクリックします。

    デモ アプリケーションでのメッセージの生成

  4. [ 会議室 2 ] ボタンをクリックします。

  5. [デタッチされた要素] ツールで、[デタッチされた要素の取得] ([デタッチされた要素の取得] アイコン) アイコンをクリックします。

    [デタッチされた要素] ツールには、ページのすべてのデタッチされた要素が表示されます。 デモ アプリケーションで Room 2 に切り替えると、 Room 1 で生成されたメッセージは DOM にアタッチされなくなりますが、これらは引き続き JavaScript によって参照されます。

    デタッチされた要素ツールを使用してデタッチされた要素を取得する

ガベージ コレクションをトリガーする

次に、ブラウザーでガベージ コレクション (GC) をトリガーします。

  1. [デタッチされた要素] ツールで、[ガベージの収集] アイコン ([ガベージの収集] アイコン) をクリックします。

  2. [ デタッチされた要素の取得 ] ([デタッチされた要素の取得] アイコン) アイコンをクリックします。

[ ガベージの収集] を選択すると、ブラウザーによってガベージ コレクションが実行されます。 [ デタッチされた要素の取得] を選択すると、[ デタッチされた要素] ツールには、ガベージ コレクションできないデタッチされたすべての要素が表示されます。 これらのデタッチされた要素は、アプリケーションによって再利用されない場合、メモリ リークになる可能性があります。

デタッチされた要素を保持する JavaScript コードを特定する

ガベージ コレクションできないデタッチされた要素が見つかったら、[デタッチされた要素] ツールの [ 分析 ] ([分析] アイコン) ボタンを使用して、 デタッチされた 要素を参照しているページで実行されている JavaScript コードを特定できます。 [分析] ボタンは、ヒープ スナップショットを受け取り、デタッチされた要素の ID にヒープ内の場所を設定します。

ヒープ スナップショットの詳細については、「 メモリ ツールを使用してヒープ スナップショットを記録する」を参照してください。

デタッチされた要素を参照する JavaScript コードを識別するには:

  1. [デタッチされた要素] ツールで、[分析] ([分析] アイコン) アイコンをクリックします。

    メモリ ツールは、DevTools の下部にあるクイック ビュー ツール バーで開きます。

    デタッチされた要素ツールでデタッチされた要素を分析する

  2. [デタッチされた要素] ツールで、デタッチされた要素の [Id] フィールドを選択します。

    メモリ ツールは、デタッチされた要素を参照しているヒープ内のオブジェクトを自動的に選択します。 次のオブジェクト を Retainers と呼びます。

    デタッチされた要素ツールからヒープ スナップショットを参照する

  3. メモリ ツールで、リンクroom.js:13 を選択します。

    [ソース] ツールがアクティビティ バーで開き、room.jsファイルの 13 行目が表示されます。

  4. hide()room.jsの関数では、デモ アプリケーションの JavaScript コードによって、ルーム内の各メッセージが配列にunmounted追加されます。 配列は unmounted 、デタッチされた要素を参照しているオブジェクトです。

    デタッチされた要素を保持している JavaScript の識別

これで、デタッチされた要素がブラウザーによってガベージ コレクションされるのを妨げているリテーナーが特定されました。

他のノードが保持される DOM ノードを特定する

DOM は完全に接続されたグラフであるため、1 つの DOM ノードが JavaScript によってメモリに保持されると、他の DOM ノードが保持される可能性があります。

ツリー全体が保持される原因となっているデタッチツリー内の原因となるノードを特定するには:

  1. [ 要素のデタッチ ] ([要素のデタッチ] アイコン) アイコンをクリックして、デタッチされたツリー内の親子リンクを破棄します。

  2. [ ガベージの収集 ] アイコン ([ガベージの収集] アイコン) をクリックします。

    親子リンクは、デタッチされたツリー内で削除されます。

    デタッチされた要素ツールの [要素のデタッチ] ボタン

選択したターゲットを別の配信元に変更する

[選択したターゲット] ドロップダウン リストを使用して、異なる配信元またはフレームからデタッチされた要素をチェックできます。

  1. [ 選択したターゲット ] ドロップダウン リストをクリックします。

    [選択したターゲット] ドロップダウン リストでは、さまざまな配信元を選択できます

  2. 別の配信元を選択します。

新しい原点は、[ デタッチされた要素 ] ツールに表示されます。

その他の考慮事項

メモリ リークを探すときは、リークはアプリケーションのコンテキストに依存する可能性があることを覚えておいてください。 デモ アプリケーションでは、ブラウザーでガベージ コレクションできないデタッチされた要素が見つかり、デタッチされた要素を保持している JavaScript を特定しました。 ただし、デモ アプリケーションのコンテキストでは、チャット メッセージの一覧を保持して、ユーザーが Room 1 に戻るとメッセージ ログが保持されるようにするのが理にかなっています。

次の図は、ユーザーが 会議室 2 から会議室1 に戻るときに再アタッチされるメッセージの形式でデタッチされた要素を示しています。

デタッチされた要素は、Room 1 に戻るときに DOM に再アタッチされます

同様に、ソーシャル メディアのフィードは、ユーザーが要素をスクロールしたときに要素を切り離し、ユーザーがスクロールして戻るときに DOM に再アタッチする場合があります。 デタッチされた要素は必ずしもメモリ リークを示すわけではありません。また、メモリ リークはデタッチされた要素によって常に発生するとは限りません。

実行時間の長いアプリでは、わずか数キロバイトの小さなメモリ リークによって、時間の経過と同時にパフォーマンスが著しく低下する可能性があります。 React フレームワークを使用する Web 開発者は、Reactが DOM の仮想化されたコピーを保持していることを認識しています。 コンポーネントのマウントを適切に解除できないと、アプリケーションが仮想 DOM の大部分をリークする可能性があります。

このデモ アプリとそのリークは人工的です。 運用 Web サイトまたはアプリでデタッチされた要素ツールをテストします。 デタッチされた要素ツールで問題が発生する可能性がある場合は、Microsoft Edge DevTools チームに問い合わせて、デタッチされた要素ツールとメモリ リーク デバッグに関するフィードバックを送信してください。