Compartilhar via


O formato de arquivo heap instantâneo

Investigar o uso de memória em aplicativos Web pode ser difícil. A ferramenta Memória DevTools permite que você explore todos os objetos alocados na memória, pelo seu aplicativo Web, tomando um heap instantâneo. Essas informações são úteis para investigações de desempenho porque você pode descobrir quais objetos estão consumindo mais memória.

No entanto, às vezes, talvez seja necessário se concentrar em partes específicas dos dados de memória que a ferramenta Memória não mostra. Nesse caso, use DevTools para exportar todo o conjunto de dados de memória como um .heapsnapshot arquivo JSON.

Este artigo descreve a estrutura e o conteúdo dos .heapsnapshot arquivos JSON para que você possa criar suas próprias ferramentas de visualização e análise.

Gravar um heap instantâneo

Para exportar um .heapsnapshot arquivo, primeiro você precisa registrar um heap instantâneo na ferramenta Memória, da seguinte maneira:

  1. No Microsoft Edge, navegue até o site do qual você deseja exportar os dados.

  2. Pressione Ctrl+Shift+I (Windows, Linux) ou Command+Option+I (macOS) para abrir o Devtools.

  3. Abra a ferramenta Memória .

  4. Selecione Heap instantâneo e clique em Tomar instantâneo.

Para obter mais informações, consulte Registrar instantâneos de heap usando a ferramenta Memória.

Exportar e exibir um .heapsnapshot arquivo

Depois de registrar um heap instantâneo, você pode exportá-lo.

  1. Na barra lateral esquerda da ferramenta Memória, clique em Salvar ao lado do heap instantâneo item que você acabou de gravar.

  2. Altere a extensão do arquivo de .heapsnapshot para .json, para facilitar a abertura do arquivo em um editor de texto.

  3. Abra o arquivo salvo em um editor de texto, como Visual Studio Code.

  4. Para facilitar a leitura do JSON, em Visual Studio Code, clique com o botão direito do mouse em qualquer lugar do código e selecione Formatar documento.

Geralmente, o arquivo resultante .heapsnapshot é diferente sempre que você grava e exporta um heap instantâneo. Instantâneos de heap são gerados dinamicamente, com base no conteúdo do aplicativo Web que está sendo inspecionado atualmente em DevTools.

Visão geral do formato de .heapsnapshot arquivo

A memória usada por um aplicativo Web é organizada como um grafo pelo V8, que é o mecanismo JavaScript usado pelo Microsoft Edge. Um grafo é um tipo de dados composto por nós (pontos no grafo) e bordas (links entre os pontos).

Os dados no .heapsnapshot arquivo representam a memória do aplicativo Web que grafa com eficiência e facilita a transferência de grupos de dados entre o processo do navegador e o DevTools. O .heapsnapshot arquivo contém uma representação achatada das relações entre nós e bordas, como um objeto JSON que contém matrizes de números e cadeias de caracteres. O arquivo tem uma .heapsnapshot extensão de nome de arquivo e contém dados formatados por JSON.

Os dados têm duas partes main:

  • Os metadados, que contém todas as informações necessárias para analisar as matrizes de dados que representam o grafo de memória.
  • Os dados de matrizes, que contêm os dados reais necessários para recriar o grafo.

Atualizando essa documentação de formato de dados

O formato do arquivo, conforme documentado abaixo, pode ser alterado à medida que v8 .heapsnapshot e DevTools evoluem. Se você encontrar uma discrepância na documentação, forneça comentários no repositório MicrosoftDocs/desenvolvedor de borda.

Esquema dos .heapsnapshot dados

Estrutura de nível superior

Os .heapsnapshot dados JSON contêm um objeto raiz que tem as seguintes propriedades:

{
    "snapshot": {},
    "nodes": [],
    "edges": [],
    "trace_function_infos": [],
    "trace_tree": [],
    "samples": [],
    "locations": [],
    "strings": []
}
Propriedade Descrição Formatar
snapshot Contém todas as informações sobre o formato dos dados do grafo de memória e seu tamanho. Object
nodes Todas as informações necessárias para recriar os nós do grafo. Para analisar esses dados, use snapshot.meta.node_types e snapshot.meta.node_fields. Array
edges Todas as informações necessárias para recriar as bordas do grafo. Para analisar esses dados, use snapshot.meta.edge_types e snapshot.meta.edge_fields. Array
trace_function_infos Ainda não documentado Array
trace_tree Ainda não documentado Array
samples Ainda não documentado Array
locations Contém informações sobre o local do script dos nós. Para analisar esses dados, use snapshot.meta.location_fields com a nodes matriz. Array
strings Uma matriz de todas as cadeias de caracteres que são mantidas na memória. Podem ser cadeias de caracteres, como cadeias de caracteres ou código definidos pelo usuário. Array

Instantâneo

{
    "snapshot": {     
        "meta": {},
        "node_count": 123,
        "edge_count": 456,
        "trace_function_count": 0
    }
    ...
}
Propriedade Descrição Formatar
meta Propriedades que contêm informações sobre a forma e o tamanho de cada objeto contido nos dados do grafo de memória. Object
node_count O número total de nós no grafo de memória. Number
edge_count O número total de bordas no grafo de memória. Number
trace_function_count O número total de funções de rastreamento no grafo de memória. Number

Metadados de instantâneo

{
    "snapshot": {
        "meta": {
            "node_fields": [],
            "node_types": [],
            "edge_fields": [],
            "edge_types": []
        }
    }
    ...
}
Propriedade Descrição Formatar
node_fields A lista de todas as propriedades necessárias para recriar um nó. Array
node_types Os tipos de todas as propriedades necessárias para recriar um nó. O número de tipos é o mesmo que o número de propriedades definidas em node_fields. Array
edge_fields A lista de todas as propriedades necessárias para recriar uma borda. Array
edge_types Os tipos de todas as propriedades necessárias para recriar uma borda. O número de tipos é o mesmo que o número de propriedades em edge_fields. Array

A seguir está um exemplo de um objeto de metadados:

{
    "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"
            ]
        }
    }
}

Nós

A nodes matriz, que está no nível superior dos .heapsnapshot dados, contém todas as informações necessárias para recriar os nós do grafo de memória.

Para analisar essa matriz, as seguintes informações são necessárias:

  • snapshot.node_count, para saber quantos nós existem.
  • snapshot.meta.node_fields, para saber quantos campos cada nó tem.

Cada nó na matriz é representado por uma série de snapshot.meta.node_fields.length números. Portanto, o número total de elementos na nodes matriz é snapshot.node_count multiplicado por snapshot.meta.node_fields.length.

Para recriar um nó, leia os números da nodes matriz por grupos de tamanho snapshot.meta.node_fields.length.

O snippet de código a seguir mostra os node_fields metadados e os dados dos dois primeiros nós no grafo:

{
    "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,
        ...
    ]
    ...
}
Índice no grupo de nós Nome Descrição
0 type O tipo de nó. Confira Tipos de nó, abaixo.
1 name O nome do nó. Esse é um número que é o índice na matriz de nível strings superior. Para localizar o nome real, use o número de índice para pesquisar a cadeia de caracteres na matriz de nível strings superior.
2 id A ID exclusiva do nó.
3 self_size O tamanho do nó em bytes.
4 edge_count O número de bordas conectadas a esse nó.
5 trace_node_id A ID do nó de rastreamento
6 detachedness Se esse nó pode ser alcançado do window objeto global. 0 significa que o nó não está desanexado; o nó pode ser alcançado do window objeto global. 1 significa que o nó é desanexado; O nó não pode ser alcançado do window objeto global.

Tipos de nó

O primeiro número no grupo de números de um nó na nodes matriz corresponde ao seu tipo. Esse número é um índice que pode ser usado para pesquisar o nome do tipo na snapshot.meta.node_types[0] matriz.

Tipo de nó Descrição
Hidden Um elemento interno V8 que não corresponde diretamente a um objeto JavaScript controlável pelo usuário. Em DevTools, todos eles aparecem no nome da categoria (sistema). Mesmo que esses objetos sejam internos, eles podem ser uma parte importante dos caminhos de retenção.
Objeto Qualquer objeto definido pelo usuário, como { x: 2 } ou new Foo(4). Os contextos, que aparecem em DevTools como sistema/contexto, contêm variáveis que precisam ser alocadas no heap porque são usadas por uma função aninhada.
Nativo Coisas que são alocadas pelo mecanismo de renderização Blink, em vez de por V8. Estes são principalmente itens DOM, como HTMLDivElement ou CSSStyleRule.
Cadeia de caracteres concatenada O resultado da concatenação de duas cadeias de caracteres com o + operador. Em vez de fazer uma nova cadeia de caracteres que contém uma cópia de todos os dados das duas cadeias de caracteres de origem, o V8 cria um ConsString objeto que contém ponteiros para as duas cadeias de caracteres de origem. De uma perspectiva JavaScript, ele atua como qualquer outra cadeia de caracteres, mas de uma perspectiva de criação de perfil de memória, é diferente.
Cadeia de caracteres fatiada O resultado de uma operação de substring, como usar String.prototype.substr ou String.prototype.substring. O V8 evita copiar dados de cadeia de caracteres criando um SlicedString, que aponta para a cadeia de caracteres original e especifica o índice de início e o comprimento. De uma perspectiva JavaScript, uma cadeia de caracteres fatiada age como qualquer outra cadeia de caracteres, mas de uma perspectiva de criação de perfil de memória, ela é diferente.
Matriz Várias listas internas, que são exibidas em DevTools com o nome da categoria (matriz). Como Hidden, essa categoria agrupa uma variedade de coisas. Muitos dos objetos aqui são nomeados (propriedades de objeto) ou (elementos de objeto), indicando que eles contêm as propriedades com chave de cadeia de caracteres ou com chave numérica de um objeto JavaScript.
Código Coisas que crescem proporcionalmente para a quantidade de script e/ou o número de vezes que as funções são executadas.
Sintético Nós sintéticos não correspondem a nada realmente alocado na memória. Estes são usados para distinguir os diferentes tipos de raízes de coleta de lixo (GC).

Bordas

Semelhante à nodes matriz, a edges matriz de nível superior contém todos os elementos necessários para recriar as bordas do grafo de memória.

Também semelhante aos nós, o número total de bordas pode ser calculado multiplicando snapshot.edge_count por snapshot.meta.edge_fields.length. As bordas também são armazenadas como uma sequência de números, que você precisará iterar por grupos de tamanho snapshot.meta.edge_fields.length.

No entanto, para ler a edges matriz corretamente, primeiro você precisa ler a nodes matriz, pois cada nó sabe quantas bordas ela tem.

Para recriar uma borda, você precisa de três informações:

  • O tipo de borda.
  • O nome ou índice de borda.
  • O nó ao qual a borda está conectada.

Por exemplo, se você ler o primeiro nó na nodes matriz e sua edge_count propriedade estiver definida como 4, os quatro primeiros grupos de snapshot.meta.edge_fields.length números na edges matriz corresponderão às quatro bordas desse nó.

Índice no grupo de borda Nome Descrição
0 type O tipo de borda. Consulte Tipos do Edge para descobrir quais são os tipos possíveis.
1 name_or_index Isso pode ser um número ou uma cadeia de caracteres. Se for um número, ele corresponderá ao índice na matriz de nível strings superior, em que o nome da borda pode ser encontrado.
2 to_node O índice dentro da matriz à nodes qual essa borda está conectada.

Tipos de borda

O primeiro número no grupo de números para uma borda na edges matriz corresponde ao seu tipo. Esse número é um índice que pode ser usado para pesquisar o nome do tipo na snapshot.meta.edge_types[0] matriz.

Tipo de borda Descrição
Interno Bordas que não correspondem a nomes visíveis em JavaScript, mas ainda são importantes. Como exemplo, as instâncias de função têm um "contexto" que representa o estado das variáveis que estavam no escopo em que a função foi definida. Não há como o código JavaScript ler diretamente o "contexto" de uma função, mas essas bordas são necessárias ao investigar retentores.
Fraco As bordas fracas não mantêm o nó ao qual estão conectados e, portanto, são omitidas da exibição Retentores. Qualquer objeto com apenas bordas fracas apontando para ele pode ser descartado pela GC (coleta de lixo).
Hidden Semelhante ao Interno, exceto que essas bordas não têm nomes exclusivos e, em vez disso, são numeradas em ordem crescente.
Shortcut Uma representação mais fácil de ler de algum outro caminho. Esse tipo raramente é usado. Por exemplo, se você usar Function.prototype.bind para criar uma função vinculada com alguns argumentos vinculados, o V8 criará um JSBoundFunction, que aponta para um FixedArray (um tipo interno), que aponta para cada argumento vinculado. Ao produzir um instantâneo, o V8 adiciona uma borda de atalho da função vinculada diretamente a cada argumento vinculado, ignorando o FixedArray.
Elemento Propriedades do objeto em que a chave é um número.

locations

A locations matriz, que está no nível superior dos .heapsnapshot dados, contém informações sobre onde alguns dos nós no instantâneo foram criados. Essa matriz consiste em uma série de números destinados a serem lidos por grupos de tamanho snapshot.meta.location_fields.length. Portanto, iríamos para snapshot.meta.location_fields saber quantos campos cada local na locations matriz tem e quais são esses campos. Por exemplo, se location_fields contiver 4 itens, a locations matriz deverá ser lida por grupos de 4.

snapshot.meta.location_fields contém as informações de cada local:

Índice em location_fields Nome Descrição
0 object_index O índice do nó na matriz associada a snapshot.nodes esse local.
1 script_id A ID do script que cria o nó associado.
2 line O número de linha em que o nó foi criado, dentro do script que criou o nó.
3 column O número da coluna em que o nó foi criado, dentro do script que criou o nó.

O exemplo de código a seguir mostra como vincular a snapshot.locations matriz à snapshot.nodes matriz:

{
    "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,
        ...
    ],
    ...
}

O primeiro local na locations matriz é 7,9,0,0,. Esse local está associado ao grupo de informações de nó que começa no índice 7 na nodes matriz. Portanto, o nó contém os seguintes pares de chave/valor:

"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,

Confira também

Para saber mais sobre o formato de .heapsnapshot arquivo, consulte o código que gera o arquivo, que é a HeapSnapshotGenerator classe em heap-snapshot-generator.h.