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

デタッチされた要素ツールは、切断されたすべての要素を Web ページで見つけて表示する 1 つの方法です。 メモリ リークを評価するその他の方法については、「メモリの問題を修正する」の「デタッチされた要素を調査するためのツール」を参照してください。

重要

デタッチされた要素ツールは非推奨です。 Microsoft Edge 130 以降、 デタッチされた要素 ツールには、ツールが非推奨であることを示すメッセージが表示されます。代わりに、 メモリ ツールの [プロファイルの種類の 選択 ] 画面で、[ デタッチされた要素 ] オプション ボタンを選択します。 Edge 専用 Chrome DevTools Protocol (CDP) 関数 EdgeDOMMemory.getDetachedNodesIds は引き続き機能しますが、代わりに を使用 DOM.getDetachedDomNodes します。

Microsoft Edge 133 では、 デタッチされた要素 ツールが削除されます。代わりに、 メモリ ツールの [プロファイルの種類の 選択 ] 画面で、[ デタッチされた要素 ] オプション ボタンを選択します。 CDP 関数 EdgeDOMMemory.getDetachedNodesIds は削除されます。代わりに を使用 DOM.getDetachedDomNodes します。

Web ページのパフォーマンスを向上させるには、DOM ツリーからデタッチされ、JavaScript コードで引き続き参照されるとは思わなかった要素を見つけます。 コードが引き続き参照しているため、ブラウザーでガベージ コレクションできないデタッチされた要素を見つけて、デタッチされた要素への JavaScript コード参照を解放します。

デタッチされた要素の一覧を表示するデタッチされた要素ツール

[デタッチされた要素] ツール。メモリ ツールにリテーナーが表示され、ソース ツールで JavaScript コードを開くリンクが表示されます。

リテーナーを表示するデタッチされた要素ツール

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

ビデオのサムネイル画像

デタッチされた要素ツールを使用してメモリ リークを修正する方法

  1. 分析する Web ページを開きます。
  2. デタッチされた要素ツールを開きます。
  3. ガベージ コレクションを実行し、JavaScript オブジェクトによって参照されなくなったすべてのノードを削除します。
  4. ガベージ コレクションできなかったデタッチされたすべての要素を取得します。
  5. デタッチされた特定の要素とその JavaScript を分析して、ツリー全体が保持される原因となっているデタッチされたツリー内の原因となるノードを特定します。

デタッチされた要素を取得し、デタッチされた要素の JavaScript を分析する

デタッチされた要素のデモ Web ページを使用して デタッチされた要素 を分析するには:

  1. デタッチ された要素のデモ Web ページ を新しいウィンドウまたはタブで開きます。

    [ Room 1 ] ボタンが最初に選択されています。 デモ Web ページの JavaScript コードでは、クラスのインスタンスを Room 使用して Room 1 のメッセージを管理します。

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

    DevTools が開きます。

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

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

    Room クラスの JavaScript インスタンスによって格納されるメッセージを生成します。

  4. デモ Web ページで、[ 高速トラフィック ] ボタンをクリックします。

    デモ Web ページでは、メッセージの生成と Web ページへの表示が開始されます。

    デモ Web ページでのメッセージの生成

  5. 一部のメッセージが表示されたら、デモ Web ページの [停止 ] ボタンをクリックします。

    各メッセージは、 <div class="message"> クラスの Room 1 インスタンス Room によって参照される要素です。 Web ページ DOM ツリーにはデタッチされた要素はありません。すべてのメッセージ要素が Room クラスの現在の Room 1 インスタンスにアタッチされているためです。

    Room クラスの別のインスタンスに変更すると、要素がデタッチされます。

  6. デモ Web ページで、クラスの別のインスタンスに対応する [会議室 2 ] ボタンを Room クリックします。

    Web ページでは、メッセージは消えます。

    ルーム 2 イニシャル ビュー

    Room クラス (<div class="message">要素) の Room 1 インスタンスに対して生成されたメッセージは DOM にアタッチされなくなりましたが、Room クラスの Room 1 インスタンスによって引き続き参照されます。 これらはデタッチされた要素であり、Web ページで再度使用しない限り、メモリ リークを引き起こす可能性があります。

    デタッチされた要素の一覧を取得します。

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

    ブラウザーはガベージ コレクションを実行し、JavaScript オブジェクトによって参照されなくなったノードを削除します。

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

    ガベージ コレクションできないデタッチされた DOM 要素が表示されます。

    [デタッチされた要素の取得] ボタン

    これらのデタッチされた要素は、アプリケーションによって再利用されない場合のメモリ リークです。

    特定のデタッチされた要素を参照する JavaScript コードを特定します。

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

    デタッチされた要素ツールの下部に、メモリ ヒープの取得スナップショット. というメッセージが簡単に表示され、[すべて完了] というメッセージが表示されます。 メモリ ツールは、DevTools の下部にあるクイック ビュー パネルで開きます。

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

    [概要] と [保持者] UI の代わりに [メモリ] ツールに [プロファイルの種類] オプション ボタンが表示されている場合は、もう一度 [分析] ([分析] アイコン) ボタンをクリックします。

  10. [デタッチされた要素] ツールの [Id] 列で、@21299 や @21783 などの ID をダブルクリックします。

    これは、メモリ ヒープ スナップショット内のいずれかの<div class="message">要素の一意識別子です。 [メモリ] ツールの [リテーナー] タブにリテーナーが表示されます。

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

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

  11. [ 保持者 ] タブのメンバーに関する unmounted リテーナー サブエントリ ( Room @54011 でマウント解除など) で リンクroom.js:13 をクリックします。

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

    room.js の 13 行目: Room コンストラクター

    unmountedは クラスのRoom配列メンバーで、コンストラクターの 19 行目で定義されています。 this.unmounted = [];

  12. クラスの メソッド内hideの 49 this.unmounted.push(el); 行目まで下にRoomスクロールします。

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

    コードは、ルーム内の各メッセージを配列に unmounted 追加します。 配列は unmounted 、デタッチされた要素を参照しているオブジェクトです。

JavaScript コードでは、デタッチされた要素がブラウザーによってガベージ コレクションされるのを妨げているリテーナー オブジェクト ( unmounted 配列) を特定しました。

ブラウザーでガベージ コレクションできないデタッチされた要素が見つかり、デタッチされた要素をまだ参照している JavaScript オブジェクトが見つかりました。 その後、JavaScript コードを変更して要素を解放し、Web ページ上のデタッチされた要素の数を減らし、Web ページのパフォーマンスと応答性を向上させることができます。

他の DOM ノードが保持される原因となっている DOM ノードを特定する

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

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

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

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

    親子リンクはデタッチされたツリー内で削除され、残りの項目は他の DOM ノードが保持される原因となった DOM ノードです。

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

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

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

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

    [選択したターゲット] ドロップダウン リストを使用して、別の配信元を選択します

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

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

デタッチされた要素とメモリ リークについて

デタッチされた要素は必ずしもメモリ リークを示すわけではありません。また、メモリ リークはデタッチされた要素によって常に発生するとは限りません。 メモリ リークは、アプリケーションのコンテキストによって異なります。

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

メモリの問題は、メモリ リーク、メモリの膨らみ、頻繁なガベージ コレクションなど、Web ページのパフォーマンスに影響します。 ユーザーの症状は次のとおりです。

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

デタッチされた要素を取得する前に GC を実行して、GC'd にできない要素のみを表示する

DOM ツリーからデタッチされ、ガベージ コレクションできない要素のみを表示するには、常に [ ガベージの収集 ] を最初にクリックし、[ デタッチされた要素の取得] をクリックします。

一部の要素は一度にデタッチされた状態で表示される場合がありますが、GC を実行するまで、Web ページの JavaScript コードによって実際に参照されているかどうかはわかりません。 デモ アプリでチャット ルームを切り替えると、Web ページは DOM からメッセージを表示するために使用される要素を削除します。 ただし、クラスの別の Room インスタンスに切り替えると、これらの要素が完全に削除されるわけではなく、これらの要素への参照がまだ存在するため、これらの要素はメモリ内に残ります。

要素を再アタッチする

デタッチされた要素のデモ Web ページでは、チャット メッセージの一覧を保持して、ユーザーが Room 1 に戻った場合にメッセージ ログが保持されるようにするのが理にかなっています。 同様に、ソーシャル メディアのフィードは、ユーザーが要素をスクロールしたときに要素を切り離し、ユーザーがスクロールして戻るときに DOM に再アタッチする場合があります。

デタッチされた要素ツールがデタッチされた要素を報告する場合、必ずしもメモリ リークとは限りません。 メモリ リークとは何か、そうでないものを決めるのはあなた次第です。 おそらく、アプリは後でそれらの要素をアタッチし直します (作成し直す必要が生じず、遅くなる可能性があります)。

DOM ノードのデタッチは、最終的にそれらのデタッチされた要素を再利用する (または削除する) 限り、便利な方法です。 デタッチされた要素ツールの値は、メモリ リークが疑われる場合に、ツールによって報告される予期しないデタッチされた DOM 要素の数が増えているかどうかをチェックできます。

実行時間の長いアプリとコンポーネントのマウント解除

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

問題の報告

デタッチされた要素機能のしくみに関する問題が発生した場合は、Microsoft Edge DevTools チームに問い合わせて、デタッチされた要素機能とメモリ リーク デバッグに関するフィードバックを送信してください。

関連項目

デモ: