# Memory Leaks Node.js: Guia Prático para Debugar

> Memory Leaks Node.js são vazamentos de memória que degradam a performance de aplicações até a queda do processo. O guia prático apresenta técnicas diretas para detecção, diagnóstico e correção, incluindo análise de heap snapshots, uso de ferramentas como Chrome DevTools e monitoramento de crescimento de memória. A abordagem ensina a identificar referências retidas, closures e caches não limpos.

*Blog Sem Juízo · Destaques · 27 de agosto de 2026 · Babi Cordeiro*

Memory leaks em Node.js podem derrubar sua aplicação silenciosamente. Aprenda a detectar, diagnosticar e corrigir vazamentos de memória com técnicas práticas e diretas.

Memory leaks em Node.js são como aquela conta que chega no fim do mês: você não percebe quando começa, mas quando vê, já virou um problema. O Node.js usa o V8, que tem um coletor de lixo eficiente, mas ele não é mágico. Se o seu código segura referências que não deveria, a memória vai crescendo até derrubar o processo. A boa notícia? Dá para achar e corrigir com método.

**O que você vai conseguir com este guia:** identificar sinais de vazamento, usar as ferramentas certas para capturar e comparar heap snapshots, e aplicar correções diretas no código. Pré-requisitos: uma aplicação Node.js rodando (versão 12 ou superior), acesso ao terminal e, de preferência, um ambiente de staging para testar sem medo.

## Passo 1: Confirme que existe um vazamento de memória

Antes de sair caçando referências, certifique-se de que o problema é real. Um pico de memória pode ser só uma carga alta momentânea. Vazamento é o que cresce de forma contínua e não volta ao normal.

Um jeito rápido: monitore o uso de memória do processo com process.memoryUsage(). Rode sua aplicação e colete a métrica em intervalos regulares, por exemplo a cada 30 segundos, durante alguns minutos ou horas. Se o heapUsed (memória do heap usada) só sobe e nunca desce de forma significativa, você tem um vazamento.

**Dica:** crie um endpoint de debug em staging que retorne process.memoryUsage() para facilitar a coleta. **Erro comum:** confundir pico de memória com vazamento. Um gráfico em dente de serra é normal; uma escada crescente é o problema.

## Passo 2: Capture heap snapshots para ver o que está na memória

O V8 permite tirar "fotos" do heap, ou seja, um retrato de todos os objetos alocados na memória. Com duas fotos em momentos diferentes, você compara e vê o que cresceu.

Use o módulo nativo v8 do Node.js:

const v8 = require('v8'); const fs = require('fs');

// Tira um snapshot e salva em arquivo const snapshot = v8.writeHeapSnapshot('snapshot-1.heapsnapshot');

Rode sua aplicação, tire um snapshot no início, deixe-a trabalhar por um tempo (ou execute uma carga de teste) e tire outro. Depois, abra os arquivos no Chrome DevTools: aba Memory, botão Load, e carregue o snapshot. O DevTools mostra a árvore de retenção, ou seja, quem está segurando cada objeto na memória.

**Dica:** use o modo Comparison no DevTools para destacar objetos que cresceram entre os snapshots. **Erro comum:** tirar snapshots cedo demais, sem dar tempo de a aplicação estabilizar ou executar os cenários que causam o vazamento.

## Passo 3: Analise os retentores e encontre a referência culpada

O snapshot mostra objetos, mas o que importa é a cadeia de referências: o que faz um objeto não ser coletado. No DevTools, selecione um objeto com memória alta e olhe a seção Retainers. Você verá a árvore de quem referencia quem, até chegar a uma raiz global, como window no navegador ou global no Node.js.

Causas comuns: listeners de eventos não removidos, timers ou intervals sem clearInterval, caches que crescem sem limite, e variáveis globais acidentais. Por exemplo, se você usa setInterval para atualizar um cache e nunca limpa o intervalo, o objeto do cache fica preso para sempre.

**Dica:** procure por objetos que aparecem em múltiplos snapshots com o mesmo tamanho, mas que deveriam ter sido liberados após uma operação. **Erro comum:** ignorar closures. Uma função que captura variáveis do escopo pai pode segurar objetos indesejados se essa função for registrada como callback e nunca for removida.

## Passo 4: Use o monitoramento contínuo para pegar vazamentos em produção

Debugging local é ótimo, mas vazamentos costumam aparecer sob carga real. Ferramentas como o inspector do Node.js (node --inspect) permitem capturar snapshots remotamente, mas isso não escala para produção. O ideal é integrar monitoramento de memória ao seu observability.

Você pode usar o process.memoryUsage() em um cron que envia métricas para um sistema de monitoramento (como Prometheus ou Datadog). Defina alertas para quando o heapUsed crescer de forma anormal ao longo de horas. O objetivo não é reagir ao pico, mas ver a tendência de crescimento.

**Dica:** capture um heap snapshot automaticamente quando a memória ultrapassar um limite, para ter o diagnóstico na hora do incidente. **Erro comum:** esperar o vazamento derrubar a aplicação para agir. Quando o processo morre, o snapshot se perde.

## Passo 5: Corrija as causas típicas e teste novamente

A correção depende da causa, mas os suspeitos habituais são:

- Listeners de eventos: use removeEventListener ou off quando não precisar mais do listener.
- Timers: sempre guarde o ID de setInterval/setTimeout e chame clearInterval/clearTimeout.
- Caches: defina um limite de tamanho ou use um TTL (tempo de vida) para expirar entradas.
- Variáveis globais: evite global.minhaVariavel; use módulos com escopo local.
- Streams e buffers: certifique-se de consumir completamente o corpo de requisições e respostas, especialmente com a Fetch API nativa. Se você não lê o body, o Node pode reter a memória.

Depois de corrigir, repita o Passo 1: monitore a memória e confirme que a curva se estabilizou. Se o problema persistir, volte aos snapshots e procure por novos retentores.

**Dica:** escreva um teste de estresse que execute a operação suspeita em loop e verifique se a memória retorna ao baseline após um global.gc(). **Erro comum:** corrigir uma causa e achar que resolveu, sem validar com snapshots antes e depois.

## Checklist final do que fizemos

- [ ] Confirmei que há vazamento com monitoramento de process.memoryUsage()
- [ ] Capturei heap snapshots em momentos diferentes
- [ ] Analisei os retentores no Chrome DevTools
- [ ] Identifiquei a referência que segura objetos sem necessidade
- [ ] Corrigi a causa (listener, timer, cache, global, stream)
- [ ] Validei a correção com novo monitoramento

## FAQ

### Como detectar memory leak em Node.js?

Use process.memoryUsage() para monitorar o heapUsed ao longo do tempo. Se a memória crescer de forma contínua e não voltar ao normal, capture heap snapshots com v8.writeHeapSnapshot() e compare-os no Chrome DevTools para achar os objetos retidos.

### O que causa memory leak em Node.js?

As causas mais comuns são listeners de eventos não removidos, timers sem clearInterval/clearTimeout, caches sem limite, variáveis globais e streams ou corpos de requisição não consumidos. Essas referências impedem o coletor de lixo de liberar memória.

### Como usar heap snapshot para debugar?

Tire um snapshot do heap antes e depois de executar o cenário que causa o vazamento, usando v8.writeHeapSnapshot(). Carregue os arquivos no Chrome DevTools e use o modo Comparison para ver quais objetos cresceram e quem os referencia.

### O que é heapUsed no Node.js?

heapUsed é uma métrica do V8 que indica a quantidade de memória atualmente usada pelo heap de objetos JavaScript. Ele faz parte do objeto retornado por process.memoryUsage(), junto com outras métricas como heapTotal e external.

### Como evitar memory leaks em produção?

Além de corrigir as causas comuns, configure monitoramento contínuo de memória com alertas de tendência de crescimento. Capture snapshots automáticos quando a memória ultrapassar um limite para facilitar o diagnóstico. Teste com carga real antes de lançar.

### Memory leak em Node.js é comum?

Sim, especialmente em aplicações de longa duração que lidam com muitas conexões ou eventos. O Node.js não vaza memória por si só, mas o uso descuidado de callbacks, timers e caches pode criar referências acidentais que impedem a coleta de lixo.

Agora que você sabe o caminho, a próxima vez que a memória subir, não vai ser surpresa. É só seguir o roteiro: monitorar, fotografar, comparar e corrigir. A internet não perdoa, mas a gente ri junto quando o vazamento vira história para contar.

---

Fonte (canonical): https://blogsemjuizo.com.br/destaques/memory-leaks-nodejs-guia-pratico-para-debugar/
