Yonatan Kra. [0. 00] Saya memiliki aplikasi yang menambahkan elemen ke DOM dan memiliki dua tombol. Tambahkan Elemen, yang menambahkan 1.000 elemen ke DOM. Untuk setiap elemen, ia mendorong ke larik elemen. Hapus Elemen melewati larik elemen, dan untuk setiap elemen, ia menghapusnya dari DOM
[0. 21] Jika saya mengklik Tambahkan Elemen, saya dapat melihatnya menambahkan elemen. Jika saya menghapus elemen, mereka akan dihapus. Saya akan membuka Chrome DevTools di tab Memory dan memilih Allocation instrumentation on timeline dan mulai merekam
[0. 39] Saya akan menambahkan elemen ke DOM, dan saya akan menghapusnya. Tambahkan beberapa lagi dan hapus juga. Sekarang saya akan menghentikan rekamannya. Mari kita lihat apa yang kita miliki. Melihat bilah biru yang menandakan alokasi memori yang bukan sampah yang dikumpulkan, kita dapat melihat bahwa kita memiliki banyak pengembangan HTML dan deklarasi gaya CSS, yang datang bersamaan dengan pengembangan. Ini adalah elemen yang dialokasikan
[1. 10] Melihat satu elemen, kita dapat melihat wadah dari elemen ini, dan salah satunya adalah array kita. Kita dapat melihat array elemen itu. Dia memegang referensi kami ke elemen DOM kami. Ini adalah alasan itu tidak dihapus dari memori. Kami menemukan kebocoran kecil di aplikasi kami. Kami akan memperbaikinya dengan cepat untuk melihat tampilannya
[1. 36] Kami hanya akan mengatur panjang array elemen untuk menghapusnya. Jika sekarang kita akan merekam lagi, dan kita akan menambahkan elemen, dan memindahkan lebarnya tiga kali, bahkan mungkin empat, jadi kita memiliki empat potongan memori yang dialokasikan, saat kita menghapus elemen, kita juga menghapus elemennya
[1. 59] Kita dapat melihat bilah abu-abu, yang menandakan memori yang dialokasikan tetapi juga merupakan sampah yang dikumpulkan dan dihapus dari memori
[2. 09] Ini memecahkan masalah kecil kebocoran memori kami yang hanya memberi tahu referensi untuk menghapus elemen. Melihat bilah abu-abu, kami melihat bahwa tidak ada elemen yang tersisa di memori setelah Hapus Elemen kami
Ketika memori yang dialokasikan tidak dikembalikan ke sistem operasi atau kumpulan memori, kami menyebutnya sebagai kebocoran memori. Dalam skenario ini, memori tidak digunakan oleh aplikasi apa pun dan digunakan secara tidak perlu. Ini menghasilkan kinerja rendah, latensi tinggi, dan sering macet
Memahami kebocoran memoriJika Anda terbiasa dengan bahasa tingkat rendah seperti C, Anda pasti pernah menggunakan malloc[]
dan free[]
. Sebaliknya, JavaScript secara otomatis mengalokasikan memori saat objek dibuat dan membebaskannya saat tidak digunakan lagi
Nah, karena dikelola secara otomatis, kami sebagai pengembang selalu mendapat kesan yang salah bahwa kami tidak perlu khawatir tentang manajemen memori di browser. Jika sebuah situs menggunakan lebih banyak memori, itu berarti tidak ada yang mengumpulkannya dan ada kebocoran memori
Pengumpul sampahJika pengumpul sampah [GC] sempurna, kebocoran memori tidak akan menjadi masalah. Masalahnya adalah algoritme mereka tidak cukup pintar untuk mendeteksi kebocoran memori;
Pengumpul sampah menjalankan proses menemukan memori yang tidak lagi digunakan oleh program dan melepaskannya kembali ke OS untuk realokasi di masa mendatang. Metode ini efektif, tetapi masih terjadi kebocoran memori. Metode tersebut tidak mampu mendeteksi setiap kebocoran, seperti referensi yang bocor
Ada dua algoritme khusus yang digunakan browser
1. Tandai dan sapuSelama mark and sweep, GC menginisialisasi semua bit mark sebagai 0. Setiap kali kita membuat objek, mark bit diatur ke 1. Bit tanda dari setiap objek yang dapat dijangkau diatur ke 1. Akhirnya, sampah GC mengumpulkan semua objek yang bit tandanya disetel ke 0
2. Algoritma penghitungan referensiPada algoritme ini, algoritme memeriksa apakah objek sudah tidak diperlukan lagi. Algoritma penghitungan referensi adalah algoritme GC paling dasar. Jika suatu objek memiliki referensi nol yang mengarah ke sana, GC mengumpulkannya
Meskipun algoritme ini tersedia, namun tidak sempurna, dan oleh karena itu, kami memerlukan beberapa alat untuk mendeteksi apakah memori bocor
Mengapa ada kebocoran memori?Banyak hal yang dapat menyebabkan kebocoran memori, dan kami akan membahasnya satu per satu
Variabel global yang tidak disengaja
function getWork[] {
this.work = “I am Memory leak”;
}// The this here refers to window object and hence this variable will be created in the window.getWork[];
Karena variabel global tidak dikumpulkan oleh GC, jika string ini menjadi terlalu besar, dapat menyebabkan kebocoran memori. Contoh serupa dari global yang tidak disengaja adalah mendeklarasikan variabel tanpa menggunakan kata kunci let
dan var
Node DOM yang terlepas
Melepaskan node DOM adalah masalah krusial. Node yang terlepas masih ada di memori karena referensi globalnya
var node = document.createElement[‘a’];_
node.id = 'id1';
document.body.appendChild[node];var main = {
Id: document.getElementById[‘id1’]
}function removeElement[]{
document.body.removeChild[document.getElementById[‘id1’]];
}// The ‘this’ here refers to window object and hence this variable will be created in the window.removeElement[];
Pada contoh di atas, fungsi removeChild
_ menghapus simpul DOM dari pohon, tetapi ID referensi di objek utama global masih tetap berada di memori dan tidak dikumpulkan dari sampah
Penutupan
Penutupan mempertahankan ruang lingkup variabel fungsi luar untuk fungsi dalam bahkan di luar ruang lingkup fungsi luar
function getScore[x] {
function score[y] {
return x + y;
}
return score;
}// The this here refers to window object and hence this variable will be created in the window.var initial = getScore[2];
var final = initial[3];
Fungsi
var node = document.createElement[‘a’];_0 di sini, yang merupakan fungsi bagian dalam, memiliki referensi global yang disebut
node.id = 'id1';
document.body.appendChild[node];var main = {
Id: document.getElementById[‘id1’]
}function removeElement[]{
document.body.removeChild[document.getElementById[‘id1’]];
}// The ‘this’ here refers to window object and hence this variable will be created in the window.removeElement[];
var node = document.createElement[‘a’];1. Referensi awal ini tidak akan pernah menjadi sampah yang dikumpulkanAlat untuk mengidentifikasi kebocoran memori
node.id = 'id1';
document.body.appendChild[node];var main = {
Id: document.getElementById[‘id1’]
}function removeElement[]{
document.body.removeChild[document.getElementById[‘id1’]];
}// The ‘this’ here refers to window object and hence this variable will be created in the window.removeElement[];
Perbandingan untuk snapshot
Kebocoran Memori Variabel Global yang Tidak Disengaja dapat dideteksi dengan pembuatan profil dengan mudah. Mari kita ambil contoh cuplikan kode yang akan menyebabkan kebocoran memori karena variabel global
var x = []
var bool = false;function grow[]{
x.push[new Array[100000].join[‘a’]];
if[bool]{
setTimeout[grow, 1000];
}
}function start[]{
grow[];
bool = true;
}function stop[]{
bool = false;
}
Untuk memeriksa kode ini, kita dapat mengambil cuplikan heap dengan membuka Panel Profil di Alat Pengembang
Di sini, warna kuning dari objek window sebenarnya menggambarkan node yang memiliki referensi langsung dari kode JS. Kita perlu memperbaiki kode di sini sehingga kita bisa menghilangkan penanda kuning
Opsi di sini adalah membuat array lokal di dalam fungsi sehingga pengumpul sampah dapat mengumpulkannya atau menghapus variabel global secara eksplisit. Anda dapat menemukan kode yang diperbaiki sebagai
var bool = false;function grow[]{_
var x = [];
x.push[new Array[100000].join[‘a’]];
if[bool]{
setTimeout[grow, 1000];
}
}function start[]{
grow[];
bool = true;
}function stop[]{
bool = false;
}
Profiler alokasi
Garis Waktu Alokasi adalah alat lain yang dapat membantu Anda melacak kebocoran memori di tumpukan JS Anda. Untuk merekam garis waktu, buka panel profil Anda dan klik mulai untuk kode yang sama yang diberikan di atas
Ketika kita mengklik tombol
var node = document.createElement[‘a’];2 seperti yang ditunjukkan pada gambar dan profil yang menggunakan profiler alokasi, kita dapat melihatnya menghasilkan garis biru seperti yang ditunjukkan pada gambar
node.id = 'id1';
document.body.appendChild[node];var main = {
Id: document.getElementById[‘id1’]
}function removeElement[]{
document.body.removeChild[document.getElementById[‘id1’]];
}// The ‘this’ here refers to window object and hence this variable will be created in the window.removeElement[];
var node = document.createElement[‘a’];3 mewakili alokasi memori baru, yang bisa menjadi kebocoran memori. Anda dapat masuk ke detail dengan memperbesar salah satu bilah biru itu. Detail di sini mewakili string panjang yang didorong ke dalam array dan tidak pernah mengumpulkan sampahKesimpulan
node.id = 'id1';
document.body.appendChild[node];var main = {
Id: document.getElementById[‘id1’]
}function removeElement[]{
document.body.removeChild[document.getElementById[‘id1’]];
}// The ‘this’ here refers to window object and hence this variable will be created in the window.removeElement[];
Pengumpul sampah diperlukan tetapi tidak cukup. Dengan demikian, intervensi manusia dengan alat dan pengetahuan yang tepat diperlukan untuk mencegah kebocoran memori
Jika Anda mengetahui pola umum di atas yang menyebabkan kebocoran memori, Anda dapat memeriksanya dengan cepat menggunakan Chrome DevTools
Jika Anda menyukai artikel ini, silakan bertepuk tangan. Tip — 50 tepukan Anda akan membuat hari saya menyenangkan
Ingin tahu lebih banyak tentang saya? . Jika Anda ingin mendapatkan pembaruan, ikuti saya di Twitter dan Medium. Jika ada yang tidak jelas atau Anda ingin menunjukkan sesuatu, silakan beri komentar di bawah