Backend
Memory Leaks em JavaScript: Diagnóstico, Causas Reais e Correção
Marcos Soares Dev.to (EN Zone)
17 views
Um processo Node.js que reinicia sozinho a cada 40 minutos raramente está com bug de lógica. Está com vazamento de memória.
O sintoma clássico: o container roda liso por meia hora, o heap_size_used sobe em degraus, o garbage collector começa a rodar com mais frequência (major GC a cada poucos segundos em vez de a cada poucos minutos), a latência p99 dobra e o orquestrador mata o pod com OOMKilled. Reiniciar resolve. Por 40 minutos.
Este post é sobre encontrar a causa, não sobre aumentar --max-old-space-size.
Como o V8 decide o que é lixo
Existe um mito persistente de que o garbage collector do JavaScript usa contagem de referências. Não usa, e essa confusão faz gente escrever código defensivo inútil.
O V8 usa mark-and-sweep com alcançabilidade a partir de um conjunto de raízes (GC roots): o objeto global, a pilha de execução atual, closures ativas, e no browser, a árvore do DOM viva. Tudo que não é alcançável a partir dessas raízes vira lixo, independentemente de quantas referências circulares exista entre os objetos.
// Isto NÃO vaza. Ciclo é irrelevante para mark-and-sweep.
function criarCicloIsolado() {
const pedido = { id: 1 };
const cliente = { nome: 'Ana' };
pedido.cliente = cliente;
cliente.ultimoPedido = pedido; // referência circular
return null; // ninguém mais alcança pedido nem cliente
}
criarCicloIsolado();
// Ambos são coletados no próximo major GC.
O heap do V8 é dividido em gerações. Objetos novos nascem na new space (Scavenger, coleta rápida e frequente, tipicamente 1-16 MB). Objetos que sobrevivem a duas coletas são promovidos para a old space, varrida pelo Mark-Compact, que é caro. Um vazamento é, quase sempre, objetos sendo promovidos para old space e nunca liberados de lá.
Isso importa na prática: se seu vazamento envolve objetos grandes e de vida curta, você não tem vazamento, tem pressão de alocação (aumenta o custo de GC mas o heap estabiliza). Se o heapUsed após um major GC forçado continua subindo, aí sim é vazamento.
// medir-heap.js — rode com: node --expose-gc medir-heap.js
// --expose-gc é a única forma confiável de medir heap "limpo" sem
// confundir lixo pendente com vazamento real.
function heapDepoisDoGC() {
global.gc(); // força major GC síncrono
const { heapUsed, external, arrayBuffers } = process.memoryUsage();
return {
heapMB: (heapUsed / 1024 / 1024).toFixed(2),
externalMB: (external / 1024 / 1024).toFixed(2),
arrayBuffersMB: (arrayBuffers / 1024 / 1024).toFixed(2),
};
}
setInterval(() => {
console.log(new Date().toISOString(), heapDepoisDoGC());
}, 10_000);
Se heapMB sobe monotonicamente ao longo de 20 amostras sob carga constante, você tem vazamento no heap JavaScript. Se heapMB fica estável mas o RSS do processo sobe, o vazamento está fora do heap do V8: Buffers, addons nativos, ou fragmentação do alocador.
Essa distinção entre linguagem e runtime é a mesma que aparece quando se discute o modelo de execução do JavaScript: a especificação da linguagem não diz nada sobre GC gerational nem sobre libuv. Tudo isso é V8 e Node.js.
As cinco causas que respondem por quase todo vazamento real
1. Listeners que nunca são removidos
O caso mais comum em Node.js e o mais comum em SPAs. Cada addEventListener ou .on() cria uma referência forte do emissor para o handler, e do handler para tudo que ele captura no escopo.
Este é um trecho. O tutorial completo, com todos os exemplos, os testes e as limitações, está em https://www.vivodecodigo.com.br/backend/memory-leaks-javascript-diagnostico-heap-snapshot-producao. Se você já passou por esse problema de outro jeito, conta nos comentários: a discussão aqui ajuda a melhorar o artigo.
Read original: https://dev.to/mrmsoares/memory-leaks-em-javascript-diagnostico-causas-reais-e-correcao-69l
← Previous
Refresh APX Skills Without Replacing Your Dev Install
Next →
How do you debug something that is allowed to be wrong?
Related
The benchmark everyone cited for "fastest backend" was archived in March, and the reason is the interesting part
Backend
56
Dev.to (EN Zone)
Finding Exoplanets in Noisy Data with Machine Learning
Backend
46
DEV Community
How to automatically find the batch size when using Accelerate with FSDP2? [D]
Backend
43
Reddit r/MachineLearning
Cross-Chain Bridge Risk Assessment: Aave V3
Backend
36
DEV Community
Comments0
No comments yet — be the first