Saiba como registrar resumos de pilha com Memória > Perfis > Resumo de pilha e encontrar 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 do DOM relacionados. Use-o para fazer capturas de tela de pilha do JS, analisar gráficos de memória, comparar instantâneos e encontrar vazamentos de memória. Para mais informações, consulte Árvore de retenção de objetos.
Capturar um instantâneo
Para criar um instantâneo de alocação heap:
- Na página em que você quer criar um perfil, abra o DevTools e navegue até o painel Memory.
- Selecione o tipo de criação de perfil Snapshot de heap, selecione uma instância de VM JavaScript e clique em Criar snapshot.
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 HEAP SNAPSHOTS.
Os snapshots mostram apenas os objetos do gráfico de memória que podem ser acessados pelo objeto global. A captura de um instantâneo sempre começa com a coleta de lixo.
Limpar snapshots
Para remover todos os snapshots, clique em
Clear all profiles:Ver snapshots
Para inspecionar instantâneos de diferentes perspectivas para diferentes finalidades, selecione uma das visualizações no menu suspenso na parte superior:
Ver | Conteúdo | Finalidade |
---|---|---|
Resumo | Objetos agrupados por nomes de construtor. | Use-o para procurar objetos e seu uso de memória 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 visão melhor da estrutura do objeto e ajuda a analisar os objetos referenciados no namespace global (janela) para descobrir o que os mantém ativos. Use-o para analisar interdições e detalhar seus objetos em um nível baixo. |
Estatísticas | Gráfico de pizza da alocação de memória | Confira os tamanhos reais das partes de memória alocadas para código, strings, matrizes JS, matrizes tipadas e objetos do sistema. |
Visualização resumida
Inicialmente, um resumo de heap é aberto na visualização Resumo, que lista os Construtores em uma coluna. É possível expandir os construtores para conferir os objetos que eles instanciaram.
Para filtrar construtores irrelevantes, digite um nome que você queira inspecionar no Filtro de classe, na parte de cima da visualização Resumo.
Os números ao lado dos nomes do construtor indicam o número total de objetos criados com o construtor. 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.
- Shallow size mostra a soma dos 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.
- Tamanho retido mostra o tamanho máximo retido entre o mesmo conjunto de objetos. O tamanho retido é a quantidade de memória que pode ser liberada ao excluir um objeto e tornar seus dependentes 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.
Filtros de construtor
A visualização Resumo permite filtrar construtores com base em casos comuns de uso ineficiente de memória.
Para usar esses filtros, selecione uma das seguintes opções no menu suspenso à direita, na barra de ações:
- Todos os objetos: todos os objetos capturados pelo snapshot atual. Definido por padrão.
- Objetos alocados antes do snapshot 1: objetos que foram criados e permaneceram na memória antes do primeiro snapshot ser capturado.
- Objetos alocados entre os snapshots 1 e 2: confira a diferença nos objetos entre o snapshot mais recente e o anterior. Cada novo snapshot adiciona um incremento desse filtro à lista suspensa.
- Strings duplicadas: valores de string armazenados várias vezes na memória.
- Objetos retidos por nós removidos: objetos que são mantidos porque um nó DOM removido os referencia.
- Objetos retidos pelo console do DevTools: objetos mantidos na memória porque foram avaliados ou interagiram com o console do DevTools.
Entradas especiais no resumo
Além de agrupar por construtores, a visualização Resumo também agrupa objetos por:
- funções integradas, como
Array
ouObject
; - Elementos HTML agrupados pelas respectivas tags, por exemplo,
<div>
,<a>
,<img>
, entre outras. - Funções definidas no código.
- Categorias especiais que não são baseadas em construtores.
(array)
Essa categoria inclui vários objetos internos semelhantes a matrizes que não correspondem diretamente aos objetos visíveis no JavaScript.
Por exemplo, o conteúdo de objetos JavaScript Array
é 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 que o V8 precisa para executar funções definidas pelo JavaScript ou WebAssembly. Cada função pode ser representada de várias maneiras, de pequena e lenta a grande e rápida.
O V8 gerencia automaticamente o uso da memória nesta categoria. Se uma função for executada muitas vezes, o V8 usará mais memória para essa função e, assim, poderá executá-la com mais rapidez. Se uma função não é executada por algum tempo, o V8 pode limpar os dados internos dela.
(concatenated string)
Quando V8 concatena duas strings, como no operador JavaScript +
, ele pode optar por representar o resultado internamente como uma "string concatenada". também conhecida como estrutura de dados da corda.
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. Da perspectiva do código JavaScript, são apenas strings normais e 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 das classes C++, use o Chrome for Testing e faça o seguinte:
- Abra o DevTools e ative as Configurações > Experimentos > Mostrar opção para expor elementos internos em snapshots de heap.
- Abra o painel Memória, selecione Snapshot do heap e ative Expor componentes internos (inclui detalhes adicionais específicos da implementação).
- Reproduza o problema que fez com que o
InternalNode
retinha muita memória. - Tirar um instantâneo da pilha. Neste snapshot, os objetos têm nomes de classe C++ em vez de
InternalNode
.
(object shape)
Conforme descrito em Propriedades rápidas no V8, o V8 rastreia classes ocultas (ou formas) para que vários objetos com as mesmas propriedades e na mesma ordem possam ser representados de forma eficiente. A categoria contém essas classes ocultas, chamadas system / Map
(não relacionadas ao JavaScript Map
), e os dados relacionados.
(sliced string)
Quando o V8 precisa usar uma substring, como quando o código JavaScript chama String.prototype.substring()
, o V8 pode escolher alocar um objeto string fatiada 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.
Da perspectiva do código JavaScript, são apenas strings normais e se comportam como qualquer outra string. Se uma string dividida estiver retendo muita memória, o programa pode ter acionado o Problema 2869 e pode se beneficiar da adoção de etapas deliberadas para "nivelar" a string fatiada.
system / Context
Os objetos internos do tipo system / Context
contêm variáveis locais de um fechamento: um escopo JavaScript que uma função aninhada pode acessar.
Cada instância de função contém um ponteiro interno para a Context
em que ela é executada para poder acessar essas variáveis. Embora os objetos Context
não fiquem diretamente visíveis no JavaScript, você tem controle direto sobre eles.
(system)
Essa categoria contém vários objetos internos que (ainda) não foram categorizados de maneira 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 reverter a ação, 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:
- Faça um resumo do heap antes de realizar uma operação.
- Execute uma operação. Ou seja, interaja com a página de alguma forma que possa estar causando um vazamento.
- Realize uma operação reversa. Ou seja, faça a interação oposta e repita-a algumas vezes.
- Criar um segundo snapshot de heap e mudar a visualização para Comparação, comparando-o com Snapshot 1.
A visualização Comparison mostra a diferença entre dois instantâneos. Ao expandir uma entrada total, são mostradas as instâncias de objeto adicionadas e excluídas:
Visualização de contenção
A visualização Contenment é uma "vista aérea". da estrutura de objetos do seu aplicativo. Ela permite que você veja os fechamentos de funções, observe os objetos internos da VM que, juntos, compõem seus objetos JavaScript e entenda quanta memória seu aplicativo usa em um nível muito baixo.
A visualização oferece vários pontos de entrada:
- Objetos DOMWindow. Objetos globais para código JavaScript.
- Raízes GC. Raízes de GC usadas pelo coletor de lixo da VM. As raízes GC podem consistir em mapas de objeto integrados, tabelas de símbolos, pilhas de encadeamento da VM, caches de compilação, escopos de identificador e identificadores globais.
- Objetos nativos. Objetos do navegador "inseridos" na máquina virtual JavaScript para permitir a automação, por exemplo, nós do DOM e regras CSS.
A seção Retenção
A seção Retainers na parte inferior do painel Memory mostra objetos que apontam para o objeto selecionado na visualização. O painel Memory atualiza a seção Retainers quando você seleciona objetos diferentes em qualquer uma das visualizações, exceto Statistics.
Neste exemplo, a string selecionada é retida pela propriedade x
de uma instância Item
.
Ignorar retenções
Você pode ocultar as retenções para descobrir se qualquer outro objeto retém o selecionado. Com essa opção, não é necessário remover essa retenção do código antes de fazer o instantâneo da pilha novamente.
Para ocultar uma retenção, clique com o botão direito do mouse e selecione Ignorar esta retenção. As retenções ignoradas são marcadas como ignored
na coluna Distance. Para parar de ignorar todas as retenções, clique em Restaurar retenções ignoradas na barra de ações na parte superior.
Encontrar um objeto específico
Para encontrar um objeto na pilha coletada, você pode pesquisar usando Ctrl + F e inserir o ID do objeto.
Nomear funções para distinguir interdições
É muito útil nomear as funções para você poder distinguir fechamentos no instantâneo.
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;
}
Descobrir vazamentos do DOM
O criador de perfil de alocação heap pode refletir dependências bidirecionais entre objetos nativos do navegador (nós DOM e regras CSS) e objetos JavaScript. Isso ajuda a descobrir vazamentos que não existem devido a subárvores do DOM desconectadas esquecidas que flutuam por aí.
Os vazamentos no DOM podem ser maiores do que você pensa. Veja o exemplo a seguir. Quando o lixo da #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 forma recursiva até #tree
. Portanto, apenas
quando leafRef
é anulado, a árvore toda em #tree
é uma candidata para GC.