Cara JavaScript Berjalan: Engine, Event Loop, Async · 2/9
Memori: stack, heap, dan garbage collection
Di mana nilai-nilaimu sebenarnya tinggal, dan kenapa kamu hampir tidak pernah membebaskannya sendiri.
Baca 22 menit
Setelah pelajaran ini kamu bisa
- Menyebutkan apa yang tinggal di stack dan apa yang tinggal di heap
- Menjelaskan apa yang membuat sebuah value layak dibersihkan
- Menyebutkan empat cara kode JavaScript membocorkan memori
- Membersihkan timer dan listener dengan benar
Kamu tidak pernah memanggil free() di JavaScript. Memori dikembalikan untukmu — tapi hanya untuk value yang sudah tidak bisa dijangkau apa pun lagi. Memahami "dijangkau" adalah pembeda antara kode yang jalan berminggu-minggu dan kode yang harus di-restart tiap malam.
Stack dan heap
| Stack | Heap | |
|---|---|---|
| Menyimpan | Primitive, dan reference ke object | Object-nya sendiri |
| Ukuran | Kecil dan tetap | Besar dan bisa bertambah |
| Dikelola oleh | Otomatis, saat function masuk dan keluar | Garbage collector |
| Kecepatan | Sangat cepat | Lebih lambat |
| Bisa habis? | Ya — stack overflow | Ya — out of memory |
Inilah alasan mekanis di balik pelajaran soal reference di modul sebelumnya. const user = { name: "Ana" } menaruh object-nya di heap dan alamatnya di stack. Menyalin variable-nya berarti menyalin alamatnya, bukan object-nya.
Keterjangkauan
Collector-nya mulai dari sekumpulan root — object global, call stack saat ini, closure yang aktif — lalu mengikuti setiap reference yang bisa dijangkaunya. Apa pun yang tidak pernah ia sampai ke sana berarti tak terjangkau, dan memorinya bisa dikembalikan. Tidak ada faktor lain: bukan soal kamu mengisinya null atau tidak, bukan soal function yang membuatnya sudah return atau belum.
Hasil
Tekan Jalankan untuk melihat hasilnya.
Ini jalan di browser kamu, di dalam sandbox. Apa pun yang kamu tulis di sini tidak bisa merusak situs.
Empat cara kode nyata membocorkan memori
Kebocoran adalah memori yang tetap terjangkau padahal kamu sudah selesai dengannya. Di JavaScript penyebabnya hampir selalu salah satu dari empat ini.
// 1. A timer nobody stopped. It holds its callback, and the callback's closure.
const id = setInterval(() => sync(bigObject), 1000);
// fix:
clearInterval(id);
// 2. A listener nobody removed. The handler keeps the whole component alive.
element.addEventListener("scroll", onScroll);
// fix:
element.removeEventListener("scroll", onScroll); // the SAME function reference
// 3. A cache that only ever grows.
const cache = new Map();
function remember(key, value) { cache.set(key, value); } // never deleted
// fix: bound the size, or use a WeakMap when the key is an object
// 4. A detached DOM node still referenced from JavaScript.
const removed = document.getElementById("row");
removed.remove(); // gone from the page
// but `removed` still points at it, so it cannot be collectedHasil
Tekan Jalankan untuk melihat hasilnya.
Ini jalan di browser kamu, di dalam sandbox. Apa pun yang kamu tulis di sini tidak bisa merusak situs.
Tugas praktik
Di Chrome DevTools, buka tab Memory dan ambil heap snapshot dari aplikasi mana pun. Lalu pakai aplikasinya secara intensif, ambil snapshot kedua, dan pakai tampilan "Comparison" untuk melihat apa yang bertambah. Kalau object sebuah component terus bertambah setelah kamu berpindah halaman darinya, kamu menemukan kebocoran nyata.
Hasil yang diharapkan
Daftar perbandingan yang menunjukkan constructor mana yang bertambah object-nya.