Поделиться через


Формат файла кучи snapshot

Изучение использования памяти в веб-приложениях может быть сложной задачей. Средство devTools Memory позволяет исследовать все объекты, выделенные в памяти веб-приложением, принимая кучу snapshot. Эти сведения полезны для исследований производительности, так как вы можете узнать, какие объекты потребляют больше памяти.

Однако иногда может потребоваться сосредоточиться на определенных частях данных памяти, которые не отображаются в средстве "Память ". В этом случае используйте Средства разработки для экспорта всего набора данных памяти в .heapsnapshot виде JSON-файла.

В этой статье описывается структура и содержимое .heapsnapshot JSON-файлов, что позволяет создавать собственные средства визуализации и анализа.

Запись snapshot кучи

Чтобы экспортировать .heapsnapshot файл, сначала необходимо записать кучу snapshot в средстве "Память", как показано ниже.

  1. В Microsoft Edge перейдите на веб-сайт, с которого нужно экспортировать данные.

  2. Нажмите клавиши CTRL+SHIFT+I (Windows, Linux) или COMMAND+OPTION+I (macOS), чтобы открыть средства разработки.

  3. Откройте средство "Память ".

  4. Выберите Куча snapshot и нажмите кнопку Принять snapshot.

Дополнительные сведения см. в разделе Запись моментальных снимков кучи с помощью средства "Память" (тип профилирования "Куча snapshot").

Экспорт и просмотр .heapsnapshot файла

Записав кучу snapshot, вы можете экспортировать ее.

  1. На левой боковой панели средства памяти нажмите кнопку Сохранить рядом с только что записанным элементом кучи snapshot.

  2. Измените расширение файла с .heapsnapshot на .json, чтобы упростить открытие файла в текстовом редакторе.

  3. Откройте сохраненный файл в текстовом редакторе, например Visual Studio Code.

  4. Чтобы упростить чтение JSON, в Visual Studio Code щелкните правой кнопкой мыши в любом месте кода и выберите пункт Формат документа.

Как правило, результирующий .heapsnapshot файл отличается при каждой записи и экспорте кучи snapshot. Моментальные снимки кучи создаются динамически на основе содержимого веб-приложения, которое в настоящее время проверяется в средствах разработки.

Общие сведения о .heapsnapshot формате файла

Память, используемая веб-приложением, организована в виде графа версией 8, которая является подсистемой JavaScript, используемой Microsoft Edge. Граф — это тип данных, состоящий из узлов (точек на графе) и ребер (связей между точками).

Данные в .heapsnapshot файле представляют память веб-приложения, которая эффективно графирует, и упрощает передачу групп данных между процессом браузера и DevTools. Файл .heapsnapshot содержит плоское представление отношений между узлами и ребрами в виде объекта JSON, содержащего массивы чисел и строк. Файл имеет .heapsnapshot расширение имени файла и содержит данные в формате JSON.

Данные имеют две main части:

  • Метаданные, содержащие все сведения, необходимые для анализа массивов данных, представляющих граф памяти.
  • Данные массивов, которые содержат фактические данные, необходимые для повторного создания графа.

Обновление документации по этому формату данных

Формат .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 чисел. Таким образом, общее количество элементов в массиве nodes умножается snapshot.node_count на snapshot.meta.node_fields.length.

Чтобы повторно создать узел, считайте числа из массива nodes по группам размера snapshot.meta.node_fields.length.

В следующем фрагменте кода показаны метаданные node_fields и данные для первых двух узлов графа:

{
    "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 Уникальный идентификатор узла.
3 self_size Размер узла в байтах.
4 edge_count Количество ребер, подключенных к этому узлу.
5 trace_node_id Идентификатор узла трассировки
6 detachedness Можно ли получить доступ к этому узлу из глобального window объекта. 0 означает, что узел не отсоединен; узел можно получить из глобального window объекта. 1 означает, что узел отсоединен; Невозможно получить доступ к узлу из глобального window объекта.

Типы узлов

Первое число в группе чисел для узла в массиве nodes соответствует его типу. Это число является индексом, который можно использовать для поиска имени типа в массиве snapshot.meta.node_types[0] .

Тип узла Описание
Скрытый Внутренний элемент версии 8, который не соответствует напрямую объекту JavaScript, управляемому пользователем. В средствах разработки все они отображаются под именем категории (system). Несмотря на то, что эти объекты являются внутренними, они могут быть важной частью путей хранителя.
Объект Любой определяемый пользователем объект, например { x: 2 } или new Foo(4). Контексты, которые отображаются в средствах разработки в виде системы или контекста, содержат переменные, которые должны были быть выделены в куче, так как они используются вложенной функцией.
Нативный Объекты, выделенные подсистемой отрисовки Blink, а не V8. В основном это элементы DOM, такие как HTMLDivElement или CSSStyleRule.
Объединенная строка Результат объединения двух строк с оператором + . Вместо создания новой строки, содержащей копию всех данных из двух исходных строк, V8 создает ConsString объект, содержащий указатели на две исходные строки. С точки зрения JavaScript он действует так же, как и любая другая строка, но с точки зрения профилирования памяти он отличается.
Срезная строка Результат операции подстроки, например с помощью String.prototype.substr или String.prototype.substring. V8 позволяет избежать копирования строковых данных путем создания SlicedString, который указывает на исходную строку и задает начальный индекс и длину. С точки зрения JavaScript срезная строка действует как любая другая строка, но с точки зрения профилирования памяти она отличается.
Array Различные внутренние списки, которые отображаются в средствах разработки с именем категории (массив). Как и скрытый, эта категория объединяет различные вещи. Многие из объектов здесь называются (свойства объекта) или (элементы объекта), что указывает на то, что они содержат свойства с ключами строк или числовых ключей объекта JavaScript.
Код Количество операций, которые растут пропорционально объему скрипта и (или) количеству запусков функций.
Синтетический Искусственные узлы не соответствуют чему-либо, фактически выделенному в памяти. Они используются для различения различных типов корней сборки мусора (GC).

Края

Как и массив nodes , edges массив верхнего уровня содержит все элементы, необходимые для повторного создания ребер графа памяти.

Также, как и в случае с узлами, общее число ребер можно вычислить путем умножения snapshot.edge_count на snapshot.meta.edge_fields.length. Ребра также хранятся в виде последовательности чисел, для которых потребуется выполнить итерацию по группам размера snapshot.meta.edge_fields.length.

Однако для правильного чтения массива edges сначала необходимо прочитать nodes массив, так как каждый узел знает, сколько у него ребер.

Чтобы повторно создать ребро, вам потребуется три элемента информации:

  • Тип края.
  • Имя или индекс края.
  • Узел, к которому подключено ребро.

Например, если считывается первый узел в массиве nodes , а его edge_count свойству присвоено значение 4, то первые четыре группы snapshot.meta.edge_fields.length чисел в массиве edges соответствуют четырем ребрам этого узла.

Индекс в группе ребер Имя Описание
0 type Тип края. Сведения о возможных типах см. в разделе Типы Edge .
1 name_or_index Это может быть число или строка. Если это число, оно соответствует индексу в массиве верхнего уровня strings , где можно найти имя края.
2 to_node Индекс в массиве nodes , к которому подключен этот край.

Типы ребер

Первое число в группе чисел для ребра в массиве edges соответствует его типу. Это число является индексом, который можно использовать для поиска имени типа в массиве snapshot.meta.edge_types[0] .

Тип edge Описание
Внутренний Ребра, которые не соответствуют именам, видимым в JavaScript, но по-прежнему важны. Например, экземпляры функции имеют "контекст", представляющий состояние переменных, находившихся в область, где была определена функция. Код JavaScript не может напрямую считывать "контекст" функции, но эти ребра необходимы при изучении средств хранения.
Слабый Слабые ребра не поддерживают активный узел, к которому они подключены, и поэтому опущены в представлении Хранители. Любой объект со слабыми краями, указывающими на него, может быть удален сборкой мусора (GC).
Скрытый Как и в случае с внутренним, эти ребра не имеют уникальных имен и вместо этого нумеруются в порядке увеличения.
Ярлык Более удобное для чтения представление другого пути. Этот тип используется редко. Например, если вы используете Function.prototype.bind для создания связанной функции с некоторыми связанными аргументами, V8 создает JSBoundFunction, который указывает на FixedArray (внутренний тип), который указывает на каждый связанный аргумент. При создании snapshot V8 добавляет ребро ярлыка из связанной функции непосредственно к каждому связанному аргументу, минуя FixedArray.
Элемент Свойства объекта, где ключ является числом.

locations

Массивlocations, который находится на верхнем уровне .heapsnapshot данных, содержит сведения о том, где были созданы некоторые узлы в snapshot. Этот массив состоит из ряда чисел, предназначенных для считывания группами размера snapshot.meta.location_fields.length. Поэтому мы рассмотрим snapshot.meta.location_fields , сколько полей имеет каждое расположение в массиве locations и что это за поля. Например, если location_fields содержит 4 элемента, массив locations должен считываться группами из 4.

snapshot.meta.location_fields содержит сведения для каждого расположения:

Индексирование в location_fields Имя Описание
0 object_index Индекс узла в массиве snapshot.nodes , связанном с этим расположением.
1 script_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 формате файла см. в коде, который создает файл, который является классом HeapSnapshotGenerator в heap-snapshot-generator.h.