Gravar snapshots de heap

Meggin Kearney
Meggin Kearney
Sofia Emelianova
Sofia Emelianova

Aprenda a gravar snapshots de heap em Memória > Perfis > Snapshot de heap e localizar vazamentos de memória.

O criador de perfil de alocação heap mostra a distribuição de memória pelos objetos JavaScript da página e nós DOM relacionados. Use-o para tirar instantâneos da heap JS, analisar gráficos de memória, comparar instantâneos e localizar vazamentos de memória. Para mais informações, consulte Árvore de retenção de objetos.

Capturar um snapshot

Para capturar um instantâneo de alocação heap:

  1. Na página que você quer criar um perfil, abra o DevTools e navegue até o painel Memory.
  2. Selecione o tipo de criação de perfil radio_button_checked Snapshot de heap, escolha uma instância de VM JavaScript e clique em Capturar snapshot.

Um tipo de criação de perfil selecionado e uma instância de VM JavaScript.

Quando o painel Memória carrega e analisa o snapshot, ele mostra o tamanho total dos objetos JavaScript acessíveis abaixo do título do snapshot na seção SNAPSHOTS HEAP.

O tamanho total dos objetos acessíveis.

Os snapshots mostram apenas os objetos do gráfico de memória que podem ser acessados pelo objeto global. A criação de um snapshot sempre começa com a coleta de lixo.

Um instantâneo da pilha de objetos Item dispersos.

Limpar snapshots

Para remover todos os snapshots, clique em bloquear Limpar todos os perfis:

Limpar todos os perfis.

Ver snapshots

Para inspecionar snapshots de perspectivas diferentes para finalidades diferentes, selecione uma das visualizações no menu suspenso na parte superior:

Mostrar Conteúdo Finalidade
Resumo Objetos agrupados por nomes de construtor. Use-a para buscar objetos e o uso de memória deles com base no tipo. Útil para rastrear vazamentos do DOM.
Comparação Diferenças entre dois snapshots. Use-o para comparar dois (ou mais) snapshots antes e depois de uma operação. Confirme a presença e a causa de um vazamento de memória inspecionando o delta na memória liberada e na contagem de referência.
Contenção Conteúdo de heap Fornece uma melhor visualização da estrutura do objeto e ajuda a analisar objetos referenciados no namespace global (janela) para encontrar o que os mantém por perto. Use-o para analisar interdições e mergulhar nos seus objetos em um nível mais baixo.
Estatísticas Gráfico de pizza de alocação de memória Confira os tamanhos reais das partes de memória alocadas ao código, às strings, às matrizes JS, às tipadas e aos objetos do sistema.

Visualização Resumo selecionada no menu suspenso na parte superior.

Visualização de resumo

Inicialmente, um instantâneo de heap é aberto na visualização Resumo, que lista os Construtores em uma coluna. Você pode expandir construtores para ver os objetos que eles instanciaram.

A visualização Resumo com um construtor expandido.

Para filtrar construtores irrelevantes, digite um nome que você quer inspecionar no Filtro de classe na parte de cima da visualização Resumo.

Os números ao lado dos nomes dos construtores indicam o número total de objetos criados com ele. A visualização Resumo também mostra as seguintes colunas:

  • Distância mostra a distância até a raiz usando o caminho simples mais curto de nós.
  • Tamanho superficial mostra a soma de tamanhos superficiais de todos os objetos criados por um determinado construtor. O tamanho superficial é o tamanho da memória retida pelo próprio objeto. Geralmente, matrizes e strings têm tamanhos superficiais maiores. Consulte também Tamanhos de objeto.
  • O tamanho retido mostra o tamanho máximo retido entre o mesmo conjunto de objetos. O tamanho retido é o tamanho da memória que você pode liberar ao excluir um objeto e tornar os dependentes dele inacessíveis. Consulte também Tamanhos de objeto.

Quando você expande um construtor, a visualização Resumo mostra todas as instâncias dele. Cada instância recebe um detalhamento dos tamanhos superficiais e retidos nas colunas correspondentes. O número após o caractere @ é o ID exclusivo do objeto. Ele permite comparar snapshots de heap por objeto.

Entradas especiais no resumo

Além de agrupar por construtores, a visualização Resumo também agrupa objetos por:

  • Funções integradas, como Array ou Object.
  • Funções definidas no código.
  • Categorias especiais que não são baseadas em construtores.

Entradas do construtor.

(array)

Esta categoria inclui vários objetos semelhantes a matrizes internas que não correspondem diretamente aos objetos visíveis em JavaScript.

Por exemplo, o conteúdo dos objetos Array JavaScript é armazenado em um objeto interno secundário chamado (object elements)[], para facilitar o redimensionamento. Da mesma forma, as propriedades nomeadas em objetos JavaScript geralmente são armazenadas em objetos internos secundários chamados (object properties)[], que também estão listados na categoria (array).

(compiled code)

Esta categoria inclui dados internos necessários para o V8 executar funções definidas pelo JavaScript ou WebAssembly. Cada função pode ser representada de várias maneiras, desde as pequenas e lentas até as grandes e rápidas.

O V8 gerencia automaticamente o uso da memória nesta categoria. Se uma função é executada muitas vezes, o V8 usa mais memória para que ela possa ser executada mais rapidamente. Se uma função não for executada por algum tempo, o V8 pode limpar os dados internos dela.

(concatenated string)

Quando V8 concatena duas strings, como acontece com o operador JavaScript +, ele pode optar por representar o resultado internamente como uma "string concatenada", também conhecida como estrutura de dados Rope.

Em vez de copiar todos os caracteres das duas strings de origem em uma nova string, o V8 aloca um pequeno objeto com campos internos chamados first e second, que apontam para as duas strings de origem. Isso permite que o V8 economize tempo e memória. Do ponto de vista do código JavaScript, essas são apenas strings normais, que se comportam como qualquer outra string.

InternalNode

Esta categoria representa objetos alocados fora do V8, como objetos C++ definidos pelo Blink.

Para ver os nomes de classes C++, use o Chrome for Testing e faça o seguinte:

  1. Abra o DevTools e ative as configurações em Settings > Experiments > check_box Show option to expose internals in heap snapshots.
  2. Abra o painel Memory, selecione radio_button_checked Heap snapshot e ative radio_button_checked Expor internamentes (inclui outros detalhes específicos da implementação).
  3. Reproduza o problema que fez com que InternalNode retenha muita memória.
  4. Tire um instantâneo de alocação heap. Nesse snapshot, os objetos têm nomes de classe C++ em vez de InternalNode.
(object shape)

Como descrito em Propriedades rápidas no V8, o V8 rastreia classes ocultas (ou formas) para que múltiplos objetos com as mesmas propriedades e na mesma ordem possam ser representados de forma eficiente. Essa categoria contém as classes ocultas, chamadas system / Map (não relacionadas ao JavaScript Map) e dados relacionados.

(sliced string)

Quando o V8 precisa ter uma substring, como quando o código JavaScript chama String.prototype.substring(), o V8 pode optar por alocar um objeto de string em fatias em vez de copiar todos os caracteres relevantes da string original. Esse novo objeto contém um ponteiro para a string original e descreve qual intervalo de caracteres da string original usar.

Do ponto de vista do código JavaScript, essas são apenas strings normais, que se comportam como qualquer outra string. Se uma string fragmentada estiver retendo muita memória, o programa pode ter acionado o Problema 2869 e se beneficiar da execução de etapas deliberadas para "nivelar" a string.

system / Context

Os objetos internos do tipo system / Context contêm variáveis locais de uma fechamento, um escopo do JavaScript que uma função aninhada pode acessar.

Cada instância de função contém um ponteiro interno para o Context em que ela é executada, para que possa acessar essas variáveis. Embora os objetos Context não sejam diretamente visíveis no JavaScript, você tem controle direto sobre eles.

(system)

Esta categoria contém vários objetos internos que (ainda) não foram categorizados de forma mais significativa.

Visualização de comparação

A visualização Comparação permite encontrar objetos vazados comparando vários snapshots entre si. Por exemplo, realizar uma ação e revertê-la, como abrir e fechar um documento, não deve deixar objetos extras para trás.

Para verificar se uma determinada operação não cria vazamentos:

  1. Tire um instantâneo da pilha antes de executar uma operação.
  2. Execute uma operação. Ou seja, interaja com uma página de alguma forma que você acha que pode estar causando um vazamento.
  3. Realize uma operação de reversão. Ou seja, faça a interação oposta e repita algumas vezes.
  4. Tire um segundo snapshot de heap e altere a visualização para Comparação, comparando-o ao Snapshot 1.

A visualização Comparação mostra a diferença entre dois snapshots. Ao expandir uma entrada total, as instâncias de objetos adicionadas e excluídas são mostradas:

Comparando com o Snapshot 1.

Visualização de contenção

A visualização Contenção é uma visão geral da estrutura dos objetos do aplicativo. Ele permite observar fechamentos de funções, observar objetos internos da VM que, juntos, compõem seus objetos JavaScript e entender quanta memória o aplicativo usa em um nível muito baixo.

A visualização fornece vários pontos de entrada:

  • Objetos DOMWindow Objetos globais para o código JavaScript.
  • Raízes GC. Raízes de GC usadas pelo coletor de lixo da VM. As raízes de GC podem consistir em mapas de objetos integrados, tabelas de símbolos, pilhas de linhas de execução de VM, caches de compilação, escopos de identificadores e identificadores globais.
  • Objetos nativos. Os objetos de navegador são "empurrados" para dentro da máquina virtual JavaScript para permitir automação, por exemplo, nós DOM e regras CSS.

Visualização Contenment.

A seção Retentores

A seção Retentores na parte inferior do painel Memória mostra objetos que apontam para o objeto selecionado na visualização.

A seção Retentores.

Neste exemplo, a string selecionada é retida pela propriedade x de uma instância Item.

Encontrar um objeto específico

Para encontrar um objeto na heap coletada, use Ctrl + F para pesquisar e insira o ID do objeto.

Nomear funções para distinguir interdições

É muito útil nomear as funções para que você possa distinguir entre fechamentos no snapshot.

Por exemplo, o código a seguir não usa funções nomeadas:

function createLargeClosure() {
  var largeStr = new Array(1000000).join('x');

  var lC = function() { // this is NOT a named function
    return largeStr;
  };

  return lC;
}

Enquanto este exemplo faz:

function createLargeClosure() {
  var largeStr = new Array(1000000).join('x');

  var lC = function lC() { // this IS a named function
    return largeStr;
  };

  return lC;
}

Função nomeada em uma interdição.

Descobrir vazamentos do DOM

O criador de perfil de alocação heap tem a capacidade de refletir dependências bidirecionais entre objetos nativos do navegador (nós DOM e regras CSS) e objetos JavaScript. Isso ajuda a descobrir vazamentos invisíveis que ocorrem devido ao fato de subárvores do DOM desconectadas esquecidas flutuarem ao redor.

Os vazamentos no DOM podem ser maiores do que você imagina. Considere este exemplo. Quando o lixo de #tree é coletado?

  var select = document.querySelector;
  var treeRef = select("#tree");
  var leafRef = select("#leaf");
  var body = select("body");

  body.removeChild(treeRef);

  //#tree can't be GC yet due to treeRef
  treeRef = null;

  //#tree can't be GC yet due to indirect
  //reference from leafRef

  leafRef = null;
  //#NOW #tree can be garbage collected

#leaf mantém uma referência ao pai (parentNode) e de maneira recursiva até #tree. Portanto, apenas quando leafRef é nulo, a árvore toda em #tree é candidata a GC.

Subárvores DOM