Aprenda a usar o Chrome e o DevTools para encontrar problemas de memória que afetam o desempenho da página, incluindo vazamentos de memória, excesso de memória e coletas de lixo frequentes.
Resumo
- Descubra quanta memória sua página está usando com o Gerenciador de tarefas do Chrome.
- Visualize o uso da memória ao longo do tempo com as gravações da linha do tempo.
- Identifique árvores do DOM desanexadas (uma causa comum de vazamentos de memória) com instantâneos de alocação heap.
- Descubra quando uma nova memória está sendo alocada no heap de JS com as gravações da linha do tempo de alocação.
- Identificar elementos removidos retidos pela referência do JavaScript.
Visão geral
No espírito do modelo de desempenho RAIL, o foco dos seus esforços de desempenho precisa ser os usuários.
Os problemas de memória são importantes porque geralmente são perceptíveis pelos usuários. Os usuários podem perceber problemas de memória das seguintes maneiras:
- O desempenho de uma página piora progressivamente ao longo do tempo. Isso pode ser um sintoma de um vazamento de memória. Um vazamento de memória ocorre quando um bug na página faz com que ela use cada vez mais memória ao longo do tempo.
- A performance de uma página é sempre ruim. Isso pode ser um sintoma de excesso de memória. O excesso de memória ocorre quando uma página usa mais memória do que o necessário para uma velocidade de página ideal.
- A performance de uma página está atrasada ou parece pausar com frequência. Isso pode ser um sintoma de coletas de lixo frequentes. A coleta de lixo é quando o navegador recupera memória. O navegador decide quando isso acontece. Durante as coletas, todas as execuções de script são pausadas. Portanto, se o navegador estiver coletando muito lixo, a execução do script será pausada com frequência.
Inchaço de memória: quanto é "demais"?
Um vazamento de memória é fácil de definir. Se um site estiver usando cada vez mais memória, você tem um vazamento. Mas o aumento de memória é um pouco mais difícil de identificar. O que é considerado "usar muita memória"?
Não há números exatos aqui, porque dispositivos e navegadores diferentes têm recursos diferentes. A mesma página que funciona sem problemas em um smartphone sofisticado pode falhar em um smartphone mais simples.
O segredo é usar o modelo RAIL e focar nos usuários. Descubra quais dispositivos são mais usados pelos usuários e teste sua página neles. Se a experiência for consistentemente ruim, a página pode estar excedendo os recursos de memória desses dispositivos.
Monitorar o uso da memória em tempo real com o Gerenciador de Tarefas do Chrome
Use o Gerenciador de tarefas do Chrome como ponto de partida para investigar problemas de memória. O Gerenciador de tarefas é um monitor em tempo real que informa quanta memória uma página está usando.
Pressione Shift+Esc ou acesse o menu principal do Chrome e selecione Mais ferramentas > Gerenciador de tarefas para abrir o Gerenciador de tarefas.

Clique com o botão direito do mouse no cabeçalho da tabela do Gerenciador de tarefas e ative a Memória JavaScript.

Essas duas colunas mostram coisas diferentes sobre como a página está usando a memória:
- A coluna Consumo de memória representa a memória do SO. Os nós do DOM são armazenados na memória do SO. Se esse valor estiver aumentando, os nós do DOM estão sendo criados.
A coluna Memória JavaScript representa o heap de JS. Essa coluna contém dois valores. O valor que você quer é o número ativo (entre parênteses). O número ativo representa quanta memória os objetos acessíveis na página estão usando. Se esse número estiver aumentando, novos objetos estão sendo criados ou os objetos atuais estão crescendo.

Visualizar vazamentos de memória com gravações de desempenho
Também é possível usar o painel Desempenho como outro ponto de partida na investigação. O painel "Desempenho" ajuda a visualizar o uso de memória de uma página ao longo do tempo.
- Abra o painel Performance no DevTools.
- Marque a caixa de seleção Memória.
- Faça uma gravação.
Para demonstrar as gravações de memória de Desempenho, considere o seguinte código:
var x = [];
function grow() {
for (var i = 0; i < 10000; i++) {
document.body.appendChild(document.createElement('div'));
}
x.push(new Array(1000000).join('x'));
}
document.getElementById('grow').addEventListener('click', grow);
Sempre que o botão referenciado no código é pressionado, dez mil nós div são anexados
ao corpo do documento, e uma string de um milhão de caracteres x é enviada para a matriz x.
A execução desse código produz uma gravação da linha do tempo como a captura de tela a seguir:

Primeiro, uma explicação da interface do usuário. O gráfico HEAP no painel Visão geral (abaixo de NET) representa o heap de JS. Abaixo do painel Visão geral, está o painel Contador. Aqui, é possível ver o uso da memória detalhado por heap de JS (igual ao gráfico HEAP no painel Visão geral), documentos, nós do DOM, listeners e memória da GPU. Desativar uma caixa de seleção a oculta do gráfico.
Agora, uma análise do código em comparação com a captura de tela. Se você observar o contador de nós (o
gráfico verde), vai notar que ele corresponde perfeitamente ao código. A contagem de nós aumenta em
etapas discretas. É possível presumir que cada aumento na contagem de nós é uma chamada para grow(). O gráfico de heap de JS (o gráfico azul) não é tão simples. Para seguir as práticas recomendadas, a primeira queda
é, na verdade, uma coleta de lixo forçada (conseguida ao pressionar o botão collect garbage). Conforme
a gravação avança, é possível ver que o tamanho do heap de JS aumenta. Isso é natural e esperado: o
código JavaScript está criando os nós do DOM a cada clique no botão e fazendo muito trabalho ao
criar a string de um milhão de caracteres. O principal aqui é o fato de que o heap de JS termina
mais alto do que começou (o "começo" aqui é o ponto após a coleta de lixo forçada). No
mundo real, se você visse esse padrão de aumento do tamanho do heap de JS ou do nó, isso
poderia significar um vazamento de memória.
Descobrir vazamentos de memória da árvore do DOM removida com instantâneos de alocação heap
Um nó do DOM só pode ser coletado como lixo quando não há referências a ele na árvore do DOM da página ou no código JavaScript. Um nó é considerado "separado" quando é removido da árvore do DOM, mas ainda é referenciado por algum JavaScript. Os nós DOM removidos são uma causa comum de vazamentos de memória. Nesta seção, você vai aprender a usar os criadores de perfil de alocação heap do DevTools para identificar nós desanexados.
Veja um exemplo simples de nós do DOM desanexados.
var detachedTree;
function create() {
var ul = document.createElement('ul');
for (var i = 0; i < 10; i++) {
var li = document.createElement('li');
ul.appendChild(li);
}
detachedTree = ul;
}
document.getElementById('create').addEventListener('click', create);
Clicar no botão referenciado no código cria um nó ul com dez filhos li. Esses nós
são referenciados pelo código, mas não existem na árvore do DOM, então são desanexados.
Os instantâneos de alocação heap são uma forma de identificar nós desanexados. Como o nome indica, os instantâneos de alocação heap mostram como a memória é distribuída entre os objetos JS e os nós DOM da página no momento do instantâneo.
Para criar um instantâneo, abra o DevTools, acesse o painel Memória, selecione o botão de opção Instantâneo de alocação heap e pressione o botão Criar instantâneo.

O processamento e o carregamento do snapshot podem levar algum tempo. Quando terminar, selecione-o no painel à esquerda (chamado Instantâneos de alocação heap).
Digite Detached na caixa de entrada Filtro de classe para pesquisar árvores do DOM desanexadas.

Abra os acentos circunflexos para investigar uma árvore separada.

Clique em um nó para investigar mais. No painel Objetos, é possível ver mais
informações sobre o código que faz referência a ele. Por exemplo, na captura de tela a seguir, é possível ver
que a variável detachedTree está referenciando o nó. Para corrigir esse vazamento de memória específico, estude o código que usa detachedTree e garanta que ele remova a referência ao nó
quando não for mais necessário.

Identificar vazamentos de memória de heap do JS com linhas do tempo de alocação
A Linha do tempo de alocação é outra ferramenta que pode ajudar a rastrear vazamentos de memória no heap de JS.
Para demonstrar a linha do tempo de alocação, considere o seguinte código:
var x = [];
function grow() {
x.push(new Array(1000000).join('x'));
}
document.getElementById('grow').addEventListener('click', grow);
Sempre que o botão referenciado no código é pressionado, uma string de um milhão de caracteres é
adicionada à matriz x.
Para gravar uma Linha do tempo de alocação, abra o DevTools, acesse o painel Memória, selecione o botão de opção Alocações na linha do tempo, pressione o botão Gravar, execute a ação que você suspeita que está causando o vazamento de memória e pressione o botão Parar gravação quando terminar.
Durante a gravação, observe se alguma barra azul aparece na Allocation Timeline, como na captura de tela abaixo.

Essas barras azuis representam novas alocações de memória. Essas novas alocações de memória são as candidatas a vazamentos de memória. É possível ampliar uma barra para filtrar o painel Constructor e mostrar apenas os objetos que foram alocados durante o período especificado.

Expanda o objeto e clique no valor dele para ver mais detalhes no painel Object. Por
exemplo, na captura de tela abaixo, ao visualizar os detalhes do objeto recém-alocado,
é possível ver que ele foi alocado para a variável x no escopo Window.

Investigar a alocação de memória por função
Use o tipo de perfil Amostragem de alocação no painel Memória para conferir a alocação de memória por função JavaScript.

- Selecione o botão de opção Amostragem de alocação. Se houver um worker na página, você poderá selecioná-lo como o destino de criação de perfil na janela Selecionar a instância da VM JavaScript.
- Pressione o botão Iniciar.
- Realize as ações na página que você quer investigar.
- Pressione o botão Stop quando terminar todas as ações.
O DevTools mostra um detalhamento da alocação de memória por função. A visualização padrão é Heavy (Bottom Up), que mostra as funções que alocaram mais memória na parte de cima.

Identificar objetos retidos por referência JS
O perfil Elementos removidos mostra os elementos removidos que persistem porque são referenciados pelo código JavaScript.
Registre um perfil de Elementos desanexados para conferir os nós HTML exatos e a contagem de nós.

Identificar coletas de lixo frequentes
Se a página parecer pausar com frequência, talvez você tenha problemas de coleta de lixo.
Você pode usar o Gerenciador de tarefas do Chrome ou as gravações de memória da linha do tempo para identificar coletas de lixo frequentes. No Gerenciador de tarefas, valores de Memória ou Memória JavaScript que aumentam e diminuem com frequência representam coletas de lixo frequentes. Nas gravações da linha do tempo, gráficos de heap de JS ou de contagem de nós que sobem e descem com frequência indicam coletas de lixo frequentes.
Depois de identificar o problema, use uma gravação da linha do tempo de alocação para descobrir onde a memória está sendo alocada e quais funções estão causando as alocações.