メモリの問題の調査
学習の目的
この単元を完了すると、次のことができるようになります。
- [Memory (メモリ)] パネルを使ってメモリ使用量を追跡する。
- [Performance monitor (パフォーマンスモニター)] にアクセスして、JS ヒープサイズと JS イベントリスナーを監視する。
ブラウザーのクラッシュ
ブラウザーのクラッシュを引き起こす可能性のある、次の例を考えてみましょう。クライアントブラウザーのメモリリークは、ブラウザーの速度を低下させ、ブラウザーをクラッシュさせる場合があります。
Chrome ブラウザーのフリーズやクラッシュを修正する
このモジュールで取り上げる Lightning Web コンポーネントが原因でブラウザーがフリーズすることがありますが、ある便利なツールを使うことで、応答しないタブを閉じることができます。
- Chrome ブラウザーのタブセクションの空白部分を右クリックして、[Task Manager (タスクマネージャー)] を選択します。
- [Task Manager (タスクマネージャー)] の項目をクリックします。[End process (プロセスを終了)] ボタンが有効になります。
- [Task Manager (タスクマネージャー)] を閉じます。
この方法を使えば、応答していないプロセスを終了できます。
悪い例をもう 1 つ挙げて、その解決方法を見ていきましょう。
過剰なイベントリスナー数
- 開いている Bad Network アプリケーションで、[Example 2: Count Clicks (例 2: クリック数を数える)] を選択します。
- 計測の応答が遅くなるまで繰り返し [Click Me (ここをクリック)] をクリックすると、結果もクリック数と一致しない数になります。色も変わります。[Performance monitor (パフォーマンスモニター)] を使って状況を調査しましょう。
- ページを更新します。
- DevTools で [Customize and control DevTools (DevTools のカスタマイズと制御)] アイコン (
) をクリックしてメニューを展開し、[More tools (その他のツール)] > [Performance monitor (パフォーマンスモニター)] をクリックします。
パフォーマンスモニターでは、経時的にパフォーマンスを追跡します。ページ操作をしながら、パフォーマンスの変化を監視できます。
-
[JS heap size (JS ヒープサイズ)] と [JS event listeners (JS イベントリスナー)] のオプションを選択して、結果を表示します。
着目するのは、JS イベントリスナーの数です。パフォーマンスが変化してから、このページのグラフに反映されるまでに少し時間がかかる場合があります。この後の操作を続けながら、[CPU usage (CPU 使用率)]、[JS heap size (JS ヒープサイズ)]、[DOM Nodes (DOM ノード)]、[JS event listeners (JS イベントリスナー)] に注目します。
-
[Click Me (ここをクリック)] を何度かクリックします。CPU 使用率に変化はありません。DOM ノードも一定です。ところが、JS ヒープサイズと JS イベントリスナーは大幅に増加しています。
DevTools で利用できる、JS ヒープサイズの追跡のための情報を見ていきましょう。
[Memory (メモリ)] パネルを使用する
- [Performance monitor (パフォーマンスモニター)] を閉じます。
- DevTools メニューから [Memory (メモリ)] タブを選択します。
- ページを更新して、まっさらな状態から始めます。これにより、比較のためのベースラインとなるスナップショットを取得できます。
- [Memory (メモリ)] パネルの [Take snapshot (スナップショットを作成)] をクリックします。
- スナップショットが作成され、表示されるまで待ちます。(ブラウザーの速度によって、表示されるまでに数分かかることがあります。)
- 先ほどと同じように、速度が遅くなるまで [Click Me (ここをクリック)] をクリックします。
- [Profiles (プロファイル)] ヘッダーを選択し、[Take snapshot (スナップショットを作成)] をクリックして新しいスナップショットを作成します。
- スナップショットが作成されるまで待ちます。新しいスナップショットは、最初のスナップショットの下に表示されます。[Snapshot 1 (スナップショット 1)] (95.5 MB) と [Snapshot 2 (スナップショット 2)] (116 MB) では、サイズが 20.5 MB 増加しています。皆さんのスナップショットのサイズはこれとは異なる可能性があります。
2 つのスナップショットを比較してみましょう
- [Memory (メモリ)] メニューの [Perspective (視点)] リストから (現在は [Summary (概要)] に設定されています)、[Comparison (比較)] を選択します。
デフォルトでは、1 つ前のスナップショットとの比較になりますが、データの上にあるドロップダウンから選択して、比較対象のスナップショットを選択することもできます。各行には、項目ごとに 2 つのスナップショットの差異が表示されます。
- [Size Delta (サイズの差分)] 列ヘッダーをクリックして、サイズの差分の順に並び替えます。ヘッダーをクリックするたびに、並び替えオプションが切り替わります。
- サイズの差分を降順で並び替えます。
[Constructor (コンストラクター)] 列を下にスクロールしていくと、[SomeObj] コンストラクターまでは、大半がシステム項目であることが分かります。そして、この例では 6,142 の SomeObjs が作成されています。かなりの数です。
-
[SomeObj] を展開して開き、SomeObj のすべてのインスタンスを表示します。
各 SomeObj インスタンスに対して、メモリ内の SomeObj の JavaScript コンストラクターがリストされています。この例では、63 行目の example2_CountClicks.js ファイルがこれに相当します。
-
[SomeObj] を 1 つ選択して、[Object (オブジェクト)] ペインで詳細を表示します。([Object (オブジェクト)] ペインは、[Constructor (コンストラクター)] ペインと [Retainers (リテイナー)] ペインの下にあります。)
[Object (オブジェクト)] ペインの詳細の 2 行目にある最初のコンテキストに、81 行目のオブジェクト example2_CountClicks.js を生成するコールのファイルと場所が表示されています。
-
[example2_CountClicks.js] のリンクをクリックして、[Sources (ソース)] パネルでファイルを開きます。
81 行目は listenForEvent メソッドの一部で、SomeObj の新しいインスタンスを作成し、作成したインスタンスをクリックイベントに対する addEventListener で使用します。つまり、本文がクリックされると、そのクリックイベントに対する EventListener が新たに本文に追加されます。問題は、リスナーが一度もクリーンアップされないため、メモリリークが発生する点です。
[Elements (要素)] タブで [Event Listeners (イベントリスナー)] を確認することもできます。
- [Elements (要素)] タブを選択します。
-
body タグを選択して、[Event Listeners (イベントリスナー)] を選択します。
-
[click (クリック)] イベントを展開します。
ここには、すべてのクリックによって追加された (本文の) リスナーがすべて表示されています。典型的なメモリリークです。ブラウザーの速度が低下し、クラッシュする原因となる可能性があります。
イベントリスナーの追加には、注意が必要です。リスナーの適切なクリーンアップは、適切な Lightning Web コンポーネントの作成に欠かせません。イベントおよびリスナーの詳細は、「リソース」セクションを参照してください。
ここまでに、Web ブラウザーで利用できる一部の開発者ツールの使い方を紹介しました。Lightning Web コンポーネントのトラブルシューティングにおける、ネットワークやメモリの問題の調査に役立ててください。
リソース
- MDN Web Docs: EventTarget.addEventListener()
- Lightning Web Components Dev Guide (Lightning Web コンポーネント開発者ガイド): Run Code When a Component Renders (コンポーネント表示時のコードの実行)
- Lightning Web Components Dev Guide (Lightning Web コンポーネント開発者ガイド): イベントの作成とディスパッチ
- Lightning Web Components Dev Guide (Lightning Web コンポーネント開発者ガイド): Access Elements the Component Owns (コンポーネントが所有する要素へのアクセス)