Em JavaScript, vazamentos de memória ocorrem quando objetos não utilizados não são coletados pelo garbage collector. Abaixo estão cenários comuns e soluções práticas.
Variáveis Globais Acidentais
Ao omitir declarações de variáveis, o JavaScript pode criar globais indesejadas.
// Variável global não declarada
function inicializar() {
mensagem = "global acidental"; // Sem let/const/var
}
function configurar() {
this.configGlobal = "configuração global"; // 'this' aponta para o objeto global em modo não estrito
}
configurar();
Solução: Utilize o modo estrito e declare variáveis explicitamente.
"use strict";
function inicializarSeguro() {
let mensagemLocal = "variável local";
}
Temproizadores e Callbacks Esquecidos
Temporizadores e manipuladores de eventos podem manter referências a objetos, impedindo a coleta de lixo.
// Temporizador não limpo
const dadosCarregados = carregarDados();
setInterval(() => {
const elemento = document.getElementById('info');
if (elemento) {
elemento.textContent = JSON.stringify(dadosCarregados);
}
}, 1000);
// Ouvinte de evento não removido
const botao = document.getElementById('botao');
botao.addEventListener('clique', manipularClique);
Solução: Limpe temporizadores e remova ouvintes quando não necessários.
// Limpar temporizador
const idIntervalo = setInterval(funcaoCallback, 1000);
clearInterval(idIntervalo);
// Remover ouvinte
botao.removeEventListener('clique', manipularClique);
Referências ao DOM
Manter referências a elementos DOM removidos impede a liberação de memória.
const elementosCache = {
botao: document.getElementById('botao'),
imagem: document.getElementById('imagem')
};
function removerElemento() {
document.body.removeChild(document.getElementById('botao'));
// elementosCache.botao ainda aponta para o elemento removido
}
Solução: Defina referências como null após o uso.
function limparReferencias() {
elementosCache.botao = null;
elementosCache.imagem = null;
}
Closures
Closures podem capturar grandes volumes de dados, mantendo-os na memória.
function criarClosure() {
const arrayGrande = new Array(100000).fill('x');
return () => {
console.log(arrayGrande.length);
// arrayGrande permanece referenciado
};
}
const funcaoClosure = criarClosure();
Solução: Libere closures não utilizadas.
function usarClosure() {
let funcao = criarClosure();
funcao(); // Usar
funcao = null; // Liberar referência
}
Objetos de Cache Ilimitados
Caches sem limites crescem indefinidamente, consumindo memória.
const cache = {};
function armazenarCache(chave, valor) {
cache[chave] = valor; // Sem controle de tamanho
}
Solução: Implemente caches com tamanho máximo.
class CacheLimitado {
constructor(tamanhoMaximo = 50) {
this.tamanhoMaximo = tamanhoMaximo;
this.armazenamento = new Map();
}
adicionar(chave, valor) {
if (this.armazenamento.size >= this.tamanhoMaximo) {
const primeiraChave = this.armazenamento.keys().next().value;
this.armazenamento.delete(primeiraChave);
}
this.armazenamento.set(chave, valor);
}
}
Nós DOM Separados
Nós removidos da árvore DOM, mas mantidos em variáveis JavaScript, não são coletados.
let arvoreSeparada;
function gerarEstrutura() {
const lista = document.createElement('ul');
for (let i = 0; i < 5; i++) {
const item = document.createElement('li');
lista.appendChild(item);
}
arvoreSeparada = lista; // Referência mantida sem adicionar ao DOM
}
gerarEstrutura();
Solução: Limpe referências ou adicione ao DOM conforme necessário.
Ouvintes de Evento em Componentes
Em applicações SPA, ouvintes não removidos após a destruição de componentes causam leaks.
class Componente {
constructor() {
this.aoRedimensionar = this.aoRedimensionar.bind(this);
window.addEventListener('resize', this.aoRedimensionar);
}
aoRedimensionar() {
// Lógica
}
// Sem método de limpeza
}
Solução: Implemetne métodos de limpeza.
class ComponenteSeguro {
constructor() {
this.aoRedimensionar = this.aoRedimensionar.bind(this);
window.addEventListener('resize', this.aoRedimensionar);
}
destruir() {
window.removeEventListener('resize', this.aoRedimensionar);
}
}
Práticas Recomendadas
- Use o modo estrito para evitar variáveis globais acidentais.
- Limpe temporizadores, ouvintes e closures após o uso.
- Evite referências desnecessárias a elementos DOM.
- Implemente limpeza em componentes destruídos.
- Utilize
WeakMapouWeakSetpara referências fracas.
// Exemplo com WeakMap
const mapaFraco = new WeakMap();
let elemento = document.getElementById('alvo');
mapaFraco.set(elemento, 'dados');
// Quando elemento é removido, a entrada no WeakMap é coletada automaticamente
Seguir essas práticas reduz significativamente vazamentos de memória em aplicações JavaScript.