Deteksi Memory Leak
Memory leak terjadi ketika aplikasi mengalokasikan memori tetapi tidak pernah melepaskannya kembali. Seiring waktu, pemakaian memori terus bertambah hingga akhirnya aplikasi menjadi lambat atau crash.
Penyebab Umum Memory Leak
1. Event Listener yang Tidak Di-cleanup
// ❌ Leak: listener terus menumpuk setiap mount
useEffect(() => {
window.addEventListener("resize", handleResize);
// Lupa cleanup!
}, []);
// ✅ Selalu cleanup saat unmount
useEffect(() => {
window.addEventListener("resize", handleResize);
return () => window.removeEventListener("resize", handleResize);
}, []);
2. setInterval / setTimeout yang Tidak Di-clear
// ❌ Interval berjalan terus meski komponen sudah unmount
useEffect(() => {
const id = setInterval(fetchData, 5000);
// Lupa clearInterval!
}, []);
// ✅ Clear saat cleanup
useEffect(() => {
const id = setInterval(fetchData, 5000);
return () => clearInterval(id);
}, []);
3. Reference ke DOM atau Object yang Sudah Tidak Dipakai
// ❌ Map terus tumbuh, tidak ada yang dihapus
const cache = new Map();
function cacheData(key, data) {
cache.set(key, data); // Entry tidak pernah dihapus
}
// ✅ Gunakan WeakMap untuk referensi lemah
const cache = new WeakMap();
// Atau hapus entry yang sudah tidak diperlukan
cache.delete(key);
4. Closure yang Menahan Referensi
// ❌ Closure menahan referensi ke array besar
function createHandler() {
const largeData = new Array(1000000).fill("data");
return function handler() {
// handler ini menahan largeData di memory!
console.log("handled");
};
}
Cara Mendeteksi Memory Leak
Chrome DevTools — Memory Tab
- Buka DevTools → tab Memory
- Pilih Heap snapshot → klik Take snapshot
- Lakukan aksi yang dicurigai menyebabkan leak
- Ambil snapshot lagi
- Bandingkan kedua snapshot — cari object yang terus bertambah
Allocation Timeline
- Pilih Allocation instrumentation on timeline
- Klik Start
- Lakukan beberapa kali aksi yang dicurigai
- Klik Stop
- Cari "retained" objects (tidak di-garbage collect)
Task Manager Browser
Shift+Esc → buka Task Manager Chrome. Amati kolom Memory footprint halaman kamu — jika terus naik saat digunakan, ada indikasi leak.
Mengukur Memory di JavaScript
// API Memory (hanya di Chrome)
const memory = performance.memory;
console.log({
used: Math.round(memory.usedJSHeapSize / 1024 / 1024) + " MB",
total: Math.round(memory.totalJSHeapSize / 1024 / 1024) + " MB",
limit: Math.round(memory.jsHeapSizeLimit / 1024 / 1024) + " MB",
});
// Snapshot sederhana untuk monitoring
function takeMemorySnapshot(label) {
if (performance.memory) {
console.log(`[${label}] Heap: ${Math.round(performance.memory.usedJSHeapSize / 1024 / 1024)}MB`);
}
}
Pola Deteksi Memory Leak
// Deteksi tren naik pada snapshot heap
function detectLeak(snapshots) {
if (snapshots.length < 3) return false;
// Hitung apakah memory konsisten naik
let increasingCount = 0;
for (let i = 1; i < snapshots.length; i++) {
if (snapshots[i].heapUsed > snapshots[i - 1].heapUsed) {
increasingCount++;
}
}
// Jika >80% snapshot menunjukkan kenaikan → kemungkinan leak
return increasingCount / (snapshots.length - 1) > 0.8;
}
Tips Mencegah Memory Leak
- Selalu cleanup useEffect — kembalikan fungsi cleanup
- Gunakan AbortController untuk membatalkan fetch saat unmount
- WeakRef dan WeakMap untuk cache yang tidak menghambat GC
- Hindari global variables yang menyimpan data besar
- Profile secara berkala — jangan tunggu sampai ada laporan lambat
Contoh: AbortController untuk Fetch
useEffect(() => {
const controller = new AbortController();
fetch("/api/data", { signal: controller.signal })
.then(res => res.json())
.then(setData)
.catch(err => {
if (err.name !== "AbortError") console.error(err);
});
return () => controller.abort(); // ✅ Batalkan fetch saat unmount
}, []);