メモリの問題を解決する

Chrome と DevTools を使用して、ページ パフォーマンスに影響するメモリの問題(以下を含む)を見つける方法を確認します。 メモリリーク、メモリ肥大化、頻繁なガベージコレクション

概要

  • Chrome タスク マネージャーを使用して、ページの現在のメモリ容量を確認します。
  • タイムライン記録を使用して、一定期間のメモリ使用量を可視化します。
  • ヒープ スナップショットを使用して、デタッチされた DOM ツリー(メモリリークの一般的な原因)を特定します。
  • Allocation Timeline 記録により、JS ヒープに新しいメモリが割り当てられるタイミングがわかります。

概要

RAIL パフォーマンス モデルの精神に基づき、パフォーマンスの取り組みで重視すべき点は次のとおりです。 説明します。

メモリの問題は、ユーザーが気付くことが多いため重要です。ユーザーはメモリを 報告されます。

  • ページのパフォーマンスが次第に低下している。これはおそらく 防ぐことができます。メモリリークとは、ページにバグがあり、 メモリを徐々に増やすことができます。
  • ページのパフォーマンスが一貫して低い。これはメモリ肥大化の兆候である可能性があります。メモリー 肥大化とは、ページで使用されるメモリが、最適なページ速度を実現するために必要以上に多い状態のことです。
  • ページのパフォーマンスが遅れる、または頻繁に一時停止しているように見える。次の症状の可能性があります。 頻繁にガベージ コレクションを行います。ガベージ コレクションは、ブラウザがメモリを回収することです。ブラウザ このタイミングを決定します。収集中は、すべてのスクリプトの実行が一時停止します。ブラウザが ガベージコレクションが行われると スクリプトの実行が頻繁に一時停止します

メモリ肥大化: 「多すぎる」状態はどれくらいか

メモリリークは簡単に定義できます。サイトのメモリ使用量が次第に増加している場合は、 水漏れが発生していますしかし、メモリの肥大化の特定は少し困難です。「メモリ使用量が多すぎる」と判断するのは、どのようなことですか。

デバイスやブラウザによって機能が異なるため、具体的な数値はありません。 ハイエンドのスマートフォンではスムーズに動作するページが、ローエンドのスマートフォンではクラッシュすることがあります。

ここで重要なのは、RAIL モデルを使用して、ユーザーに焦点を当てることです。人気のデバイスを調べる それらのデバイスでページをテストしますエクスペリエンスが一貫して ページがそれらのデバイスのメモリ能力を超えている可能性があります。

Chrome タスク マネージャーでメモリ使用量をリアルタイムでモニタリング

メモリの問題を調査する際は、まず Chrome タスク マネージャーを使用します。タスク マネージャー ページが現在使用しているメモリ量を表示するリアルタイム モニターです。

  1. Shift+Esc キーを押すか、Chrome のメインメニューに移動して [その他のツール] >タスク マネージャーから タスク マネージャーを開きます。

    タスク マネージャーを開く

  2. タスク マネージャーのテーブル ヘッダーを右クリックし、[JavaScript メモリ] を有効にします。

    JS メモリの有効化

次の 2 つの列は、ページでのメモリの使用状況に関するさまざまな情報を示します。

  • [メモリ] 列はネイティブ メモリを表します。DOM ノードはネイティブ メモリに保存されます。もし 値が増え続けると、DOM ノードが作成されます。
  • [JavaScript メモリ] 列は JS ヒープを表します。この列には 2 つの値が含まれます。「 関心のある値は、実際の数値(かっこで囲まれた数値)です。現在の電話番号 は、ページ上で到達可能なオブジェクトが使用しているメモリ量を表します。この番号が 新しいオブジェクトの作成、または既存のオブジェクトの増加のいずれかが発生します。

パフォーマンス記録でメモリリークを可視化する

[パフォーマンス] パネルは、調査の別の出発点としても使用できます。パフォーマンス パネルを使用すると、ページのメモリ使用量の推移を可視化できます。

  1. DevTools で [Performance] パネルを開きます。
  2. [メモリ] チェックボックスをオンにします。
  3. 録画する
で確認できます。

パフォーマンスに関するメモリ記録のデモを行うために、以下のコードを考えてみましょう。

var x = [];

function grow() {
  for (var i = 0; i < 10000; i++) {
    document.body.appendChild(document.createElement('div'));
  }
  x.push(new Array(1000000).join('x'));
}

document.getElementById('grow').addEventListener('click', grow);

コード内で参照されているボタンが押されるたびに、1 万個の div ノードが追加されます。 ドキュメントの本文に追加され、100 万個の x 文字の文字列が x 配列にプッシュされます。 このコードを実行すると、次のスクリーンショットのようなタイムライン記録が生成されます。

シンプルな成長の例

まず、ユーザー インターフェースについて説明します。[Overview] ペイン(下)の HEAP グラフ NET)は JS ヒープを表します。[概要] ペインの下には [カウンタ] ペインがあります。ここでは、 JS ヒープごとのメモリ使用量の表示([Overview] ペインの [HEAP] グラフと同じ) ドキュメント、DOM ノード、リスナー、GPU メモリです。チェックボックスをオフにすると、そのチェックボックスはグラフに表示されなくなります。

では、コードをスクリーンショットと比較してみましょう。ノードカウンタ( 緑色のグラフ)が表示されていれば、コードと完全に一致していることがわかります。ノードの数は、 あります。ノード数が増加するたびに、grow() が呼び出されると想定できます。JS ヒープグラフ(青いグラフ)はそれほど単純ではありません。ベスト プラクティスに従い、最初の低下は 実際には、強制ガベージ コレクション([collect garbage] ボタンを押すと実行されます)です。として 記録が進むと JS ヒープサイズが急増していることがわかります。これは当然のことで、想定内の動作です。 JavaScript のコードは、ボタンがクリックされるたびに DOM ノードを作成し、そのノードがクリックされると 100 万文字の文字列を作成します。ここで重要なのは JS ヒープが終了して (ここでは、ガベージ コレクションが強制された後のポイントが「開始」となります)。イン 実際のところ、このような JS ヒープサイズまたはノードサイズが増大するパターンを見た場合、 メモリリークが発生している可能性があります

ヒープ スナップショットで DOM ツリーのデタッチされたメモリリークを検出する

DOM ノードがガベージ コレクションの対象になるのは、 DOM ツリーや JavaScript コードです。ノードは「切断された」状態DOM ツリーから削除されても 一部の JavaScript は引き続き参照します。デタッチされた DOM ノードは、メモリリークの一般的な原因です。この 」セクションでは、DevTools を使用してデタッチされたノードを特定するためのヒープ プロファイラ。

デタッチされた DOM ノードの簡単な例を次に示します。

var detachedTree;

function create() {
  var ul = document.createElement('ul');
  for (var i = 0; i < 10; i++) {
    var li = document.createElement('li');
    ul.appendChild(li);
  }
  detachedTree = ul;
}

document.getElementById('create').addEventListener('click', create);

コードで参照されているボタンをクリックすると、10 個の li 子を持つ ul ノードが作成されます。これらのノードは はコードからは参照されますが、DOM ツリーには存在しないため、デタッチされます。

ヒープ スナップショットは、切断されたノードを特定する方法の一つです。名前のとおりヒープのスナップショットは ページの読み込み時点でのページの JS オブジェクトと DOM ノード間でのメモリの配分を あります。

スナップショットを作成するには、DevTools を開いて [Memory] パネルに移動し、[Heap [スナップショット] ラジオボタンを選択して、[スナップショットを取得] ボタンを押します。

ヒープ スナップショットを取得

スナップショットの処理と読み込みには時間がかかることがあります。完了したら左側から パネル(HEAP SNAPSHOTS)は、

[クラスフィルタ] テキスト ボックスに「Detached」と入力して、デタッチされた DOM ツリーを検索します。

接続解除されたノードのフィルタリング

カラットを開いて、分離されたツリーを調べます。

分離ツリーの調査

黄色でハイライト表示されたノードには、JavaScript コードからの直接参照が含まれています。ハイライト表示されたノード 赤色には直接参照はありません。それらが生きているのは、黄色のノードの 表示されます。通常は、黄色のノードに注目します。黄色のノードが表示されなくなるようにコードを修正 必要以上に長く存続し、ノードの一部である赤のノードも 表示されます。

詳しく調べるには、黄色のノードをクリックします。[オブジェクト] ペインでは、他のオブジェクトと コードに関する情報が表示されます。たとえば、以下のスクリーンショットでは、 detachedTree 変数がノードを参照していることを確認します。このメモリリークを修復するには detachedTree を使用するコードを調べ、ノードへの参照を削除することを確認します。 通知を受け取れます

黄色のノードの調査

Allocation Timeline で JS ヒープのメモリリークを特定する

Allocation Timeline も、JS ヒープのメモリリークの追跡に役立つツールです。

割り当てタイムラインを説明するために、次のコードを考えてみましょう。

var x = [];

function grow() {
  x.push(new Array(1000000).join('x'));
}

document.getElementById('grow').addEventListener('click', grow);

コード内で参照されているボタンが押されるたびに、100 万文字の文字列が x 配列に追加されます。

割り当てタイムラインを記録するには、DevTools を開いて [Profiles] パネルに移動し、[Record] [割り当てのタイムライン] ラジオボタンで [開始] ボタンを押し、想定しているアクションを実行します。 原因がメモリリークの場合は、[録画を停止] ボタンを押します (録画を停止ボタン) 完了です。

録画中に、割り当てタイムラインに青色のバー(例: 以下のスクリーンショットを参照してください。

新しい割り当て

これらの青いバーは、新しいメモリ割り当てを表します。これらの新しいメモリ割り当てが 見ていきますバーをズームすると、[Constructor] ペインがフィルタされ、目的のオブジェクトのみを表示できます。 割り当てられているかを確認できます

割り当てタイムラインの拡大

オブジェクトを開いて値をクリックすると、[Object] ペインにオブジェクトの詳細が表示されます。対象 たとえば、以下のスクリーンショットのように、新しく割り当てられたオブジェクトの詳細を表示して、 Window スコープの x 変数に割り当てられていることがわかります。

オブジェクトの詳細

関数ごとにメモリ割り当てを調査する

JavaScript 関数別にメモリ割り当てを表示するには、[Memory] パネルの [Allocation Sampling] タイプを使用します。

レコード割り当てプロファイラ

  1. [Allocation Sampling] ラジオボタンを選択します。ページ上にワーカーがいる場合は [Start] ボタンの横にあるプルダウン メニューを使用して、プロファイリング ターゲットとして選択できます。
  2. [Start] ボタンを押します。
  3. 調査するページで操作を行います。
  4. すべての操作が終了したら、[停止] ボタンを押します。

DevTools に、関数ごとのメモリ割り当ての内訳が表示されます。デフォルトのビューは [高(下)] です。 Up) が表示されます。これにより、最も多くのメモリを割り当てた関数が一番上に表示されます。

割り当てプロファイル

頻繁に行われるガベージ コレクションを特定する

ページが頻繁に一時停止する場合は、ガベージ コレクションに問題がある可能性があります。

Chrome タスク マネージャーまたはタイムラインのメモリ記録を使用して、頻繁に発生するごみを特定できる ありますタスク マネージャーでのメモリまたは JavaScript メモリの頻繁な上昇と下降 頻繁なガベージ コレクションを表します。タイムライン記録で、頻繁に上昇と下降が発生する JS ヒープまたはノード数のグラフは、ガベージ コレクションが頻繁に行われていることを示します。

問題を特定したら、割り当てタイムラインの記録を使用して、 割り当てを生じさせている関数を特定できます。