ヒープスナップショットファイル形式

Web アプリケーションでのメモリ使用量の調査は困難な場合があります。 DevTools Memory ツールを使用すると、ヒープをスナップショットすることで、Web アプリケーションによってメモリに割り当てられているすべてのオブジェクトを探索できます。 この情報は、最も多くのメモリを消費しているオブジェクトを確認できるため、パフォーマンスの調査に役立ちます。

ただし、 メモリ ツールに 表示されないメモリ データの特定の部分に焦点を当てる必要がある場合があります。 この場合は、DevTools を使用して、メモリ データのセット全体を .heapsnapshot JSON ファイルとしてエクスポートします。

この記事では、独自の視覚化と分析ツールを構築できるように、JSON ファイルの .heapsnapshot 構造と内容について説明します。

ヒープ スナップショットを記録する

ファイルを.heapsnapshotエクスポートするには、まず、次のように、メモリ ツールでヒープ スナップショットを記録する必要があります。

  1. Microsoft Edge で、データをエクスポートする Web サイトに移動します。

  2. Ctrl + Shift + I (Windows、Linux) または Command + Option + I (macOS) を押して Devtools を開きます。

  3. メモリ ツールを開きます。

  4. [ヒープ スナップショット] を選択し、[スナップショットの取得] をクリックします。

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

ファイルのエクスポートと表示.heapsnapshot

ヒープ スナップショットを記録したら、それをエクスポートできます。

  1. メモリ ツールの左側のサイドバーで、記録したヒープ スナップショット項目の横にある [保存] をクリックします。

  2. ファイル拡張子を から .heapsnapshot.json変更すると、テキスト エディターでファイルを簡単に開くことができます。

  3. Visual Studio Code などのテキスト エディターで保存したファイルを開きます。

  4. JSON を読みやすくするには、Visual Studio Code でコード内の任意の場所を右クリックし、[ ドキュメントの書式設定] を選択します。

通常、結果.heapsnapshotのファイルは、ヒープ スナップショットを記録してエクスポートするたびに異なります。 ヒープ スナップショットは、DevTools で現在検査されている Web アプリケーションの内容に基づいて動的に生成されます。

ファイル形式の .heapsnapshot 概要

Web アプリケーションによって使用されるメモリは、Microsoft Edge で使用される JavaScript エンジンである V8 によってグラフとして編成されます。 グラフは、 ノード (グラフ上のポイント) と エッジ (ポイント間のリンク) で構成されるデータ型です。

ファイル内の .heapsnapshot データは、効率的にグラフ化する Web アプリのメモリを表し、ブラウザー プロセスと DevTools の間でデータのグループを転送しやすくなります。 ファイルには .heapsnapshot 、数値と文字列の配列を含む JSON オブジェクトとして、ノードとエッジ間の関係のフラット化された表現が含まれています。 ファイルにはファイル名拡張子があり .heapsnapshot 、JSON 形式のデータが含まれています。

データには、次の 2 つのメイン部分があります。

  • メモリ グラフを表すデータの配列を解析するために必要なすべての情報を含むメタデータ。
  • 配列データ。グラフの再作成に必要な実際のデータが含まれます。

このデータ形式のドキュメントの更新

以下に .heapsnapshot 記載されているように、ファイルの形式は、V8 と DevTools の進化に伴って変更される可能性があります。 ドキュメントに不一致が見つかる場合は、 MicrosoftDocs/edge-developer リポジトリでフィードバックを提供してください。

データの .heapsnapshot スキーマ

最上位レベルの構造

.heapsnapshot JSON データには、次のプロパティを持つルート オブジェクトが含まれています。

{
    "snapshot": {},
    "nodes": [],
    "edges": [],
    "trace_function_infos": [],
    "trace_tree": [],
    "samples": [],
    "locations": [],
    "strings": []
}
プロパティ 説明 フォーマット
snapshot メモリ グラフ データの形式とそのサイズに関するすべての情報が含まれます。 Object
nodes グラフのノードを再作成するために必要なすべての情報。 このデータを解析するには、 と を使用 snapshot.meta.node_types します snapshot.meta.node_fields Array
edges グラフの端を再作成するために必要なすべての情報。 このデータを解析するには、 と を使用 snapshot.meta.edge_types します snapshot.meta.edge_fields Array
trace_function_infos まだ文書化されていません Array
trace_tree まだ文書化されていません Array
samples まだ文書化されていません Array
locations ノードのスクリプトの場所に関する情報が含まれます。 このデータを解析するには、 配列と共に を使用 snapshot.meta.location_fields します nodes Array
strings メモリに保持されているすべての文字列の配列。 ユーザー定義文字列やコードなど、任意の文字列を指定できます。 Array

スナップショット

{
    "snapshot": {     
        "meta": {},
        "node_count": 123,
        "edge_count": 456,
        "trace_function_count": 0
    }
    ...
}
プロパティ 説明 フォーマット
meta メモリ グラフ データに含まれるすべてのオブジェクトの図形とサイズに関する情報を含むプロパティ。 Object
node_count メモリ グラフ内のノードの合計数。 Number
edge_count メモリ グラフ内のエッジの合計数。 Number
trace_function_count メモリ グラフ内のトレース関数の合計数。 Number

スナップショット メタデータ

{
    "snapshot": {
        "meta": {
            "node_fields": [],
            "node_types": [],
            "edge_fields": [],
            "edge_types": []
        }
    }
    ...
}
プロパティ 説明 フォーマット
node_fields ノードを再作成するために必要なすべてのプロパティの一覧。 Array
node_types ノードの再作成に必要なすべてのプロパティの種類。 型の数は、 で node_fields定義されているプロパティの数と同じです。 Array
edge_fields エッジを再作成するために必要なすべてのプロパティの一覧。 Array
edge_types エッジを再作成するために必要なすべてのプロパティの型。 型の数は、 の edge_fieldsプロパティの数と同じです。 Array

メタデータ オブジェクトの例を次に示します。

{
    "snapshot": {
        "meta": {
            "node_fields": [
                "type",
                "name",
                "id",
                "self_size",
                "edge_count",
                "trace_node_id",
                "detachedness"
            ],
            "node_types": [
                [
                    "hidden",
                    "array",
                    "string",
                    "object",
                    "code",
                    "closure",
                    "regexp",
                    "number",
                    "native",
                    "synthetic",
                    "concatenated string",
                    "sliced string",
                    "symbol",
                    "bigint",
                    "object shape"
                ],
                "string",
                "number",
                "number",
                "number",
                "number",
                "number"
            ],
            "edge_fields": [
                "type",
                "name_or_index",
                "to_node"
            ],
            "edge_types": [
                [
                    "context",
                    "element",
                    "property",
                    "internal",
                    "hidden",
                    "shortcut",
                    "weak"
                ],
                "string_or_number",
                "node"
            ]
        }
    }
}

Nodes

nodesデータの.heapsnapshot最上位にある配列には、メモリ グラフのノードを再作成するために必要なすべての情報が含まれています。

この配列を解析するには、次の情報が必要です。

  • snapshot.node_countは、ノードの数を知るために使用されます。
  • snapshot.meta.node_fieldsを使用して、各ノードに含まれるフィールドの数を確認します。

配列内の各ノードは、一連の snapshot.meta.node_fields.length 数値で表されます。 そのため、配列内の要素の合計数に nodessnapshot.node_count が乗算されます snapshot.meta.node_fields.length

ノードを再作成するには、サイズ snapshot.meta.node_fields.lengthのグループで配列から数値をnodes読み取る。

次のコード スニペットは、グラフ内の node_fields 最初の 2 つのノードのメタデータとデータを示しています。

{
    "snapshot": {
        "meta": {
            "node_fields": [
                "type",
                "name",
                "id",
                "self_size",
                "edge_count",
                "trace_node_id",
                "detachedness"
            ]
            ...
        }
        ...
    },
    "nodes": [
        9,1,1,0,10,0,0,
        2,1,79,12,1,0,0,
        ...
    ]
    ...
}
ノード グループ内のインデックス 名前 説明
0 type ノードの種類。 以下の 「ノードの種類」を参照してください。
1 name ノードの名前。 これは、最上位の strings 配列のインデックスである数値です。 実際の名前を見つけるには、インデックス番号を使用して、最上位の strings 配列内の文字列を検索します。
2 id ノードの一意の ID。
3 self_size ノードのサイズ (バイト単位)。
4 edge_count このノードに接続されているエッジの数。
5 trace_node_id トレース ノードの ID
6 detachedness このノードにグローバル オブジェクトから window 到達できるかどうか。 0 ノードがデタッチされていないことを意味します。ノードはグローバル オブジェクトから window 到達できます。 1 ノードがデタッチされていることを意味します。ノードにグローバル オブジェクトから window 到達できません。

ノードの種類

配列内のノードの数値グループの最初の nodes 数値は、その型に対応します。 この番号は、配列内 snapshot.meta.node_types[0] の型名を検索するために使用できるインデックスです。

ノードの種類 説明
Hidden ユーザーが制御できる JavaScript オブジェクトに直接対応しない V8 内部要素。 DevTools では、これらはすべてカテゴリ名 (システム) の下に表示されます。 これらのオブジェクトは内部的であっても、リテーナー パスの重要な部分になる可能性があります。
オブジェクト または new Foo(4)などの{ x: 2 }ユーザー定義オブジェクト。 DevTools に システム/コンテキストとして表示されるコンテキストは、入れ子になった関数によって使用されるため、ヒープに割り当てる必要があった変数を保持します。
ネイティブ V8 ではなく、Blink レンダリング エンジンによって割り当てられるもの。 これらは主に、 や CSSStyleRuleなどの HTMLDivElement DOM 項目です。
連結された文字列 演算子と 2 つの文字列を連結した + 結果。 V8 は、2 つのソース文字列のすべてのデータのコピーを含む新しい文字列を作成するのではなく、2 つのソース文字列へのポインターを含むオブジェクトを作成 ConsString します。 JavaScript の観点からは、他の文字列と同様に動作しますが、メモリ プロファイリングの観点からは異なります。
スライスされた文字列 または String.prototype.substrString.prototype.substringなどの部分文字列操作の結果。 V8 では、元の文字列を指し示し、開始インデックスと長さを指定する を作成 SlicedStringすることで、文字列データのコピーを回避します。 JavaScript の観点からは、スライスされた文字列は他の文字列と同様に機能しますが、メモリ プロファイリングの観点からは異なります。
配列 カテゴリ名 (配列) を使用して DevTools に表示されるさまざまな内部リスト。 非表示と同様に、このカテゴリはさまざまなものをグループ化します。 ここでのオブジェクトの多くは、名前 (オブジェクト プロパティ) または (オブジェクト要素) であり、JavaScript オブジェクトの文字列キー付きプロパティまたは数値キー付きプロパティが含まれていることを示します。
コード スクリプトの量や関数の実行回数に比例して増加するもの。
合成 合成ノードは、メモリ内で実際に割り当てられたものには対応しません。 これらは、さまざまな種類のガベージ コレクション (GC) ルートを区別するために使用されます。

エッジ

配列と nodes 同様に、最上位の edges 配列には、メモリ グラフの端を再作成するために必要なすべての要素が含まれています。

ノードと同様に、エッジの合計数は を乗算snapshot.edge_countsnapshot.meta.edge_fields.lengthして計算できます。 エッジは数値のシーケンスとしても格納されます。これは、サイズ snapshot.meta.edge_fields.lengthのグループで反復処理する必要があります。

ただし、配列を edges 正しく読み取る場合は、各ノードで配列のエッジ数が nodes 認識されるため、最初に配列を読み取る必要があります。

エッジを再作成するには、次の 3 つの情報が必要です。

  • エッジの種類。
  • エッジ名またはインデックス。
  • エッジが接続されているノード。

たとえば、配列内の最初のnodesノードを読み取り、そのedge_countプロパティが 4 に設定されている場合、配列内edgesの最初の snapshot.meta.edge_fields.length 4 つの数値グループは、このノードの 4 つのエッジに対応します。

エッジ グループのインデックス 名前 説明
0 type エッジの種類。 可能 な型については、「Edge 型 」を参照してください。
1 name_or_index 数値または文字列を指定できます。 数値の場合は、最上位の strings 配列のインデックスに対応します。このインデックスは、エッジの名前を見つけることができます。
2 to_node このエッジが nodes 接続されている配列内のインデックス。

エッジの種類

配列内のエッジ edges の数値グループの最初の数値は、その型に対応します。 この番号は、配列内 snapshot.meta.edge_types[0] の型名を検索するために使用できるインデックスです。

エッジの種類 説明
内部 JavaScript で表示される名前に対応していないが、依然として重要なエッジ。 たとえば、関数インスタンスには、関数が定義されたスコープ内にあった変数の状態を表す "コンテキスト" があります。 JavaScript コードが関数の "コンテキスト" を直接読み取る方法はありませんが、リテーナーを調査するときは、これらのエッジが必要です。
弱い 弱いエッジは、接続されているノードを維持しないため、保持ビューから省略されます。 弱いエッジのみを指すオブジェクトは、ガベージ コレクション (GC) によって破棄できます。
Hidden 内部に似ていますが、これらのエッジには一意の名前がなく、代わりに番号が増える順序で番号が付けられます。
ショートカット 他のパスの読みやすい表現。 この型はまれに使用されます。 たとえば、 を使用Function.prototype.bindしてバインドされた関数をいくつかのバインドされた引数で作成する場合、V8 は、 を指す ( 内部型) を指FixedArrayす を作成JSBoundFunctionします。これは、バインドされた各引数を指します。 スナップショットを生成する場合、V8 は バインドされた関数のショートカット エッジをバインドされた各引数に直接追加し、 をバイパスしますFixedArray
要素 キーが数値であるオブジェクト プロパティ。

locations

locationsデータの.heapsnapshot最上位にある配列には、スナップショット内のノードの一部が作成された場所に関する情報が含まれています。 この配列は、サイズ snapshot.meta.location_fields.lengthのグループによって読み取られる一連の数値で構成されます。 したがって、配列内locationsの各場所に含まれるフィールドの数と、それらのフィールドが何であるかを知るために移動snapshot.meta.location_fieldsします。 たとえば、4 つの項目が含まれている場合 location_fieldslocations 配列は 4 のグループで読み取られます。

snapshot.meta.location_fields には、各場所の情報が含まれています。

でインデックスを作成する location_fields 名前 説明
0 object_index この場所に関連付けられている配列内 snapshot.nodes のノードのインデックス。
1 script_id 関連付けられたノードを作成するスクリプトの ID。
2 line ノードを作成したスクリプト内で、ノードが作成された行番号。
3 column ノードを作成したスクリプト内で、ノードが作成された列番号。

次のコード例は、配列を snapshot.locations 配列にリンクする方法を snapshot.nodes 示しています。

{
    "snapshot": {
        "meta": {
            "location_fields": [
                "object_index",
                "script_id",
                "line",
                "column"
            ]
            ...
        }
        ...
    },
    "nodes": [
        9,1,1,0,10,0,0,
        2,1,79,12,1,0,0,
        ...
    ],
    "locations":[
        7,9,0,0,
        113792,3,25,21,
        ...
    ],
    ...
}

配列の最初の locations 場所は です 7,9,0,0,。 この場所は、配列のインデックス 7 から始まるノード情報グループに nodes 関連付けられています。 そのため、ノードには次のキーと値のペアが含まれています。

"type": 2,
"name": 1,
"id": 79,
"self_size": 12,
"edge_count": 1,
"trace_node_id": 0,
"detachedness": 0,
"script_id": 9,
"line" 0,
"column": 0,

関連項目

ファイル形式の.heapsnapshot詳細については、 の クラスであるファイルを生成するコードをHeapSnapshotGeneratorheap-snapshot-generator.h参照してください。