Interactive examples to understand memory leaks and how to detect them with DevTools.
You're caching computed results for user objects. When a user logs out, their data should be garbage collected.
// This cache PREVENTS garbage collection
const userCache = new Map();
function cacheUserData(user) {
// user object stored as KEY
userCache.set(user, {
computed: heavyComputation(user),
timestamp: Date.now()
});
}
// Even after: user = null
// The Map still holds the user object!
// Memory keeps growing...
// This cache ALLOWS garbage collection
const userCache = new WeakMap();
function cacheUserData(user) {
userCache.set(user, {
computed: heavyComputation(user),
timestamp: Date.now()
});
}
// After: user = null
// WeakMap entry is automatically removed!
// Memory is freed
You process large data and return a handler function. The closure might keep the large data alive even if you don't need it anymore.
function createHandler() {
// Large data - should be temporary
const largeData = new Array(1000000).fill('x');
// Process it
const result = largeData.length;
// Return handler that DOESN'T use largeData
return function handler() {
console.log('Result:', result);
};
// But largeData is still in the closure!
// It can't be garbage collected!
}
function createHandler() {
let largeData = new Array(1000000).fill('x');
const result = largeData.length;
largeData = null; // Release reference!
return function handler() {
console.log('Result:', result);
};
// Now largeData can be garbage collected!
}
You store DOM elements in an array/object. When you remove them from the page, the JavaScript reference keeps them in memory.
const elements = [];
function addCard() {
const card = document.createElement('div');
card.innerHTML = '<img src="large-image.jpg">';
container.appendChild(card);
elements.push(card); // Store reference
}
function removeCards() {
elements.forEach(el => el.remove());
// DOM nodes removed from page...
// But 'elements' array still holds them!
// They're "detached" but not garbage collected
}