W3docs

Entendendo a Coleta de Lixo em JavaScript

A coleta de lixo é um recurso automático de gerenciamento de memória que garante uso eficiente da memória, recuperando a memória ocupada por objetos que não são mais necessários.

Introdução à Coleta de Lixo

A coleta de lixo gerencia automaticamente a memória em JavaScript. Ela libera a memória usada por dados que não são mais necessários, de forma que você quase nunca precisa alocar ou liberar memória manualmente. Esta página explica a ideia central em que todo o sistema se baseia — alcançabilidade — e então cobre o algoritmo de marcação e varredura, os vazamentos que ainda escapam, e como WeakMap/WeakSet ajudam a evitá-los.

Entender isso importa porque "automático" não significa "livre de vazamentos." O coletor remove apenas o que ele consegue provar ser inalcançável; se o seu código mantém uma referência oculta ativa, a memória permanece alocada durante toda a vida do programa.

Alcançabilidade: o conceito central

O motor não rastreia se um object está "em uso" em um sentido lógico. Ele rastreia se o object é alcançável — se existe alguma cadeia de referências que leve a ele a partir de uma raiz.

Raízes são valores que o motor sempre mantém:

  • As variáveis locais e parâmetros da função em execução no momento.
  • Variáveis e funções na cadeia atual de chamadas aninhadas.
  • Variáveis globais (propriedades de globalThis/window).

Qualquer object alcançável seguindo referências a partir de uma raiz — diretamente ou por meio de outros objects alcançáveis — é mantido. Todo o resto é lixo.

Exemplo: uma referência mantém um object vivo

javascript— editable

Explicação: O object { name: "John" } era alcançável por meio de user. Copiar a referência para admin cria um segundo caminho até ele. Definir user = null remove um caminho, mas admin ainda aponta para o object, então ele permanece alcançável e não é coletado.

Objects interligados ainda são coletados

Um mito comum é que objects que referenciam uns aos outros sobrevivem. Eles não sobrevivem — o que importa é a alcançabilidade a partir de uma raiz, não se os objects apontam uns para os outros.

javascript— editable

Explicação: obj1 e obj2 formam um ciclo, mas assim que ambas as variáveis raiz são definidas como null não há caminho de nenhuma raiz até o ciclo. A ilha inteira se torna inalcançável e elegível para coleta. É por isso que os motores JavaScript usam alcançabilidade em vez de contagem de referências simples, que vazaria em ciclos.

Como o coletor funciona: marcação e varredura

Os motores JavaScript recuperam memória com o algoritmo de marcação e varredura. Ele reduz "este object não é mais necessário" à questão precisa "este object não é mais alcançável."

  1. Marcar. Partindo das raízes, o coletor visita cada object alcançável e o marca. Em seguida, ele segue suas referências, marca esses objects, e assim por diante até que todos os objects alcançáveis sejam marcados.
  2. Varrer. Todo object que não foi marcado é inalcançável. A memória que ele ocupa é liberada.

Você não pode acionar isso manualmente e não deve tentar — não existe um gc() padrão na linguagem. Motores reais (como o V8) refinam o algoritmo básico com otimizações como a coleta geracional (objects novos morrem jovens, então verifique-os com mais frequência) e a coleta incremental (divida o trabalho em partes para evitar pausas). O modelo de alcançabilidade que você analisou acima permanece o mesmo.

Fontes comuns de vazamentos de memória

Um vazamento em JavaScript é simplesmente um object que permanece alcançável mesmo depois que seu programa terminou de usá-lo. O coletor está funcionando corretamente — ele simplesmente não consegue identificar que a referência é obsoleta. Fique atento a esses padrões.

Temporizadores e intervalos esquecidos

Um setInterval pendente (ou setTimeout) mantém seu callback vivo, e o callback mantém tudo o que ele captura em seu escopo. Se você nunca chamar clearInterval, essa memória ficará alocada durante toda a vida da página.

javascript— editable

Nós DOM desanexados

Se você remover um elemento da página mas mantiver uma referência a ele em uma variável, o nó — e toda a sua subárvore — não poderá ser coletado.

let detached = document.getElementById('list');
document.body.removeChild(detached);
// The node is gone from the page, but 'detached' still references it,
// so it stays in memory. Release it when done:
detached = null;

Ouvintes de eventos persistentes

Um ouvinte vinculado a um elemento DOM mantém tanto o elemento quanto o handler (com tudo o que ele captura) alcançáveis. Remova os ouvintes com removeEventListener quando eles não forem mais necessários:

<button id="myButton">Click me</button>
<script>
  const button = document.getElementById('myButton');
  function alertClick() {
    alert("Button clicked!");
    button.removeEventListener('click', alertClick); // free the listener after first use
  }
  button.addEventListener('click', alertClick);
</script>

O botão responde apenas ao primeiro clique: o handler se remove com removeEventListener, liberando a referência para que ela possa ser coletada pelo coletor de lixo.

Caches globais que só crescem

Um cache armazenado em um object de nível de módulo ou global mantém cada entrada alcançável para sempre, a menos que você remova explicitamente as antigas. Um Map ilimitado usado como cache é um vazamento lento clássico.

Closures que capturam mais do que você pensa

Uma closure mantém viva cada variável nos escopos que ela referencia — mesmo aquelas que ela nunca realmente usa. Retornar uma pequena função interna de uma função com variáveis locais grandes pode fixar essas variáveis locais na memória. Mantenha o escopo capturado mínimo e veja escopo de variáveis para saber como as closures retêm seu ambiente.

Como WeakMap e WeakSet ajudam

Map e Set mantêm referências fortes para suas chaves/valores, então qualquer coisa armazenada neles permanece alcançável. WeakMap e WeakSet mantêm suas chaves de forma fraca: se a única referência restante a um object é aquela dentro de um WeakMap, o object ainda pode ser coletado, e a entrada desaparece com ele.

javascript— editable

Isso torna o WeakMap ideal para associar dados extras a objects (caches, metadados, controle de nós DOM) sem forçar esses objects a viver para sempre. Como as entradas podem desaparecer a qualquer momento, WeakMap/WeakSet são deliberadamente não iteráveis e não possuem size.

Boas práticas

  • Prefira variáveis locais; elas saem de escopo automaticamente e se tornam coletáveis quando a função retorna.
  • Limite variáveis globais — elas vivem enquanto a aplicação existir. Use módulos e escopo de bloco (let/const).
  • Limpe os temporizadores (clearInterval/clearTimeout) e remova os ouvintes de eventos com removeEventListener quando eles não forem mais necessários.
  • Anule referências a nós DOM desanexados e outros objects grandes com os quais você terminou.
  • Use WeakMap/WeakSet para caches e metadados com chave de object, para que as entradas não sobrevivam às suas chaves.

Conclusão

A coleta de lixo em JavaScript é construída inteiramente sobre a alcançabilidade: o motor mantém qualquer object que ele possa alcançar a partir de uma raiz e libera o restante usando marcação e varredura, o que lida até mesmo com ciclos de referência. "Automático" ainda deixa você responsável por não manter referências obsoletas — temporizadores esquecidos, nós DOM desanexados, caches em crescimento constante e closures que capturam demais são os culpados habituais. Recorra a WeakMap e WeakSet quando quiser associar dados a objects sem mantê-los vivos.

Prática

Prática
Quais são as características ou funcionalidades da Coleta de Lixo em JavaScript com base nas informações fornecidas no artigo?
Quais são as características ou funcionalidades da Coleta de Lixo em JavaScript com base nas informações fornecidas no artigo?
Was this page helpful?