Memperbaiki masalah memori

Kayce Basques
Kayce Basques

Pelajari cara menggunakan Chrome dan DevTools untuk menemukan masalah memori yang memengaruhi performa halaman, termasuk kebocoran memori, penggelembungan memori, dan pembersihan sampah memori yang sering dilakukan.

Ringkasan

  • Ketahui berapa banyak memori yang sedang digunakan laman Anda dengan Pengelola Tugas Chrome.
  • Visualisasikan penggunaan memori seiring waktu dengan perekaman Linimasa.
  • Identifikasi hierarki DOM yang terlepas (penyebab umum kebocoran memori) dengan Snapshot Heap.
  • Cari tahu kapan memori baru dialokasikan di heap JS Anda dengan perekaman Allocation Timeline.

Ringkasan

Dengan prinsip model performa RAIL, upaya performa performa Anda harus difokuskan pada pengguna.

Masalah memori penting karena sering terlihat oleh pengguna. Pengguna dapat melihat masalah memori dengan cara berikut:

  • Performa halaman secara bertahap menjadi buruk dari waktu ke waktu. Ini mungkin merupakan gejala kebocoran memori. Kebocoran memori terjadi saat bug di halaman menyebabkan halaman menggunakan lebih banyak memori secara bertahap dari waktu ke waktu.
  • Performa halaman terus-menerus buruk. Ini mungkin adalah gejala penggelembungan memori. Penggelembungan memori terjadi saat halaman menggunakan lebih banyak memori daripada yang diperlukan untuk mendapatkan kecepatan halaman yang optimal.
  • Performa halaman tertunda atau tampak sering dijeda. Ini mungkin merupakan gejala pembersihan sampah memori yang sering. Pembersihan sampah memori terjadi saat browser mengklaim kembali memori. Browser akan menentukan kapan tindakan ini terjadi. Selama pengumpulan, semua eksekusi skrip dijeda. Jadi, jika browser sering mengumpulkan sampah, eksekusi skrip akan sering dijeda.

Penggelembungan memori: berapa banyak yang dimaksud dengan "terlalu banyak"?

Kebocoran memori mudah didefinisikan. Jika situs secara progresif menggunakan semakin banyak memori, artinya telah terjadi kebocoran. Tapi penggelembungan memori sedikit lebih sulit untuk dijabarkan. Apa yang dianggap "menggunakan terlalu banyak memori"?

Tidak ada angka yang pasti, karena perangkat dan browser yang berbeda memiliki kemampuan yang berbeda. Laman yang berjalan lancar di ponsel cerdas kelas atas bisa jadi macet di ponsel cerdas kelas bawah.

Kuncinya di sini adalah menggunakan model RAIL dan berfokus pada pengguna Anda. Cari tahu perangkat apa yang populer di kalangan pengguna, lalu uji halaman Anda di perangkat tersebut. Jika hasil yang didapat terus-menerus buruk, halaman mungkin melampaui kemampuan memori perangkat tersebut.

Memantau penggunaan memori secara real time dengan Task Manager pada Chrome

Gunakan Pengelola Tugas Chrome sebagai titik awal ke penyelidikan masalah memori. {i>Task Manager<i} adalah pemantau realtime yang memberi tahu Anda berapa banyak memori yang sedang digunakan sebuah laman.

  1. Tekan Shift+Esc atau buka menu utama Chrome, lalu pilih Alat lainnya > Pengelola tugas untuk membuka Pengelola Tugas.

    Membuka Pengelola Tugas

  2. Klik kanan header tabel Pengelola Tugas lalu aktifkan memori JavaScript.

    Mengaktifkan memori JS

Kedua kolom ini memberitahukan hal yang berbeda mengenai penggunaan memori oleh halaman Anda:

  • Kolom Memory mewakili memori native. Node DOM disimpan di memori native. Jika nilai ini meningkat, node DOM akan dibuat.
  • Kolom JavaScript Memory mewakili heap JS. Kolom ini berisi dua nilai. Nilai yang Anda minati adalah bilangan real time (angka dalam tanda kurung). Angka real time menunjukkan berapa banyak memori yang digunakan oleh objek yang dapat dijangkau di halaman Anda. Jika jumlah ini meningkat, berarti objek baru sedang dibuat atau objek yang sudah ada bertambah.

Memvisualisasikan kebocoran memori dengan Rekaman performa

Anda juga dapat menggunakan panel Performa sebagai titik awal lain dalam penyelidikan. Panel Performa membantu Anda memvisualisasikan penggunaan memori halaman dari waktu ke waktu.

  1. Buka panel Performa di DevTools.
  2. Aktifkan kotak centang Memory.
  3. Buat rekaman.

Untuk mendemonstrasikan perekaman memori Performa, pertimbangkan kode di bawah ini:

var x = [];

function grow() {
  for (var i = 0; i < 10000; i++) {
    document.body.appendChild(document.createElement('div'));
  }
  x.push(new Array(1000000).join('x'));
}

document.getElementById('grow').addEventListener('click', grow);

Setiap kali tombol yang dirujuk dalam kode ditekan, sepuluh ribu node div ditambahkan ke isi dokumen, dan string berisi satu juta karakter x dikirim ke array x. Menjalankan kode ini menghasilkan rekaman Linimasa seperti screenshot berikut:

contoh pertumbuhan sederhana

Pertama, penjelasan tentang antarmuka pengguna. Grafik HEAP di panel Overview (di bawah NET) menunjukkan heap JS. Di bawah panel Overview adalah panel Penghitung. Di sini, Anda dapat melihat penggunaan memori yang dikelompokkan menurut heap JS (sama seperti grafik HEAP di panel Overview), dokumen, node DOM, pemroses, dan memori GPU. Menonaktifkan kotak centang akan menyembunyikannya dari grafik.

Sekarang, analisis kode dibandingkan dengan {i>screenshot<i}. Jika Anda melihat penghitung node (grafik hijau), Anda dapat melihat penghitung tersebut cocok dengan kode. Jumlah {i>node<i} meningkat pada langkah-langkah diskret. Anda dapat menganggap bahwa setiap peningkatan jumlah node adalah panggilan ke grow(). Grafik heap JS (grafik biru) tidak semudah itu. Sesuai dengan praktik terbaik, penurunan pertama sebenarnya adalah pembersihan sampah memori yang dipaksakan (dicapai dengan menekan tombol mengumpulkan sampah). Saat perekaman berlangsung, Anda dapat melihat bahwa ukuran heap JS melonjak. Hal ini wajar dan diharapkan: kode JavaScript membuat node DOM pada setiap kali tombol diklik dan melakukan banyak pekerjaan saat membuat string satu juta karakter. Intinya di sini adalah fakta bahwa heap JS berakhir lebih tinggi dari dimulai ("dimulai" di sini adalah titik setelah pembersihan sampah memori paksa). Di dunia nyata, jika Anda melihat pola peningkatan ukuran heap JS atau ukuran node ini, hal itu berpotensi menyebabkan kebocoran memori.

Menemukan kebocoran memori hierarki DOM yang terlepas dengan Cuplikan Heap

Node DOM hanya dapat dibersihkan sampah memorinya jika tidak ada referensi ke node tersebut, baik dari hierarki DOM atau kode JavaScript halaman. Node dianggap "terpisah" jika dihapus dari hierarki DOM, tetapi beberapa JavaScript masih mereferensikannya. Simpul DOM yang terlepas adalah penyebab umum kebocoran memori. Bagian ini menunjukkan cara menggunakan profiler heap DevTools untuk mengidentifikasi node yang terlepas.

Berikut ini contoh sederhana simpul DOM yang terlepas.

var detachedTree;

function create() {
  var ul = document.createElement('ul');
  for (var i = 0; i < 10; i++) {
    var li = document.createElement('li');
    ul.appendChild(li);
  }
  detachedTree = ul;
}

document.getElementById('create').addEventListener('click', create);

Mengklik tombol yang direferensikan dalam kode akan membuat node ul dengan sepuluh turunan li. Node ini direferensikan oleh kode, tetapi tidak ada di hierarki DOM sehingga terlepas.

Snapshot heap adalah salah satu cara untuk mengidentifikasi node yang terlepas. Sesuai dengan namanya, snapshot heap menunjukkan distribusi memori di antara objek JS dan node DOM halaman Anda pada saat snapshot.

Untuk membuat snapshot, buka DevTools dan masuk ke panel Memory, pilih tombol pilihan Heap Snapshot, lalu tekan tombol Take Snapshot.

ambil cuplikan heap

Snapshot mungkin memerlukan beberapa waktu untuk diproses dan dimuat. Setelah selesai, pilih dari panel kiri (bernama HEAP SNAPSHOTS).

Ketik Detached di kotak teks Class filter untuk menelusuri hierarki DOM yang terlepas.

pemfilteran untuk node yang terlepas

Luaskan karat untuk menyelidiki pohon yang terlepas.

menyelidiki pohon yang terlepas

Node yang ditandai dengan warna kuning memiliki referensi langsung ke node tersebut dari kode JavaScript. Node yang ditandai merah tidak memiliki referensi langsung. Mereka hanya hidup karena merupakan bagian dari pohon node kuning. Secara umum, Anda ingin fokus pada node kuning. Perbaiki kode Anda sehingga node kuning tidak aktif selama lebih lama dari yang diperlukan, dan Anda juga menghapus node merah yang merupakan bagian dari pohon node kuning.

Klik node kuning untuk menyelidikinya lebih lanjut. Di panel Objects, Anda dapat melihat informasi selengkapnya tentang kode yang mereferensikannya. Misalnya, dalam screenshot di bawah, Anda dapat melihat bahwa variabel detachedTree mereferensikan node. Untuk memperbaiki kebocoran memori khusus ini, Anda akan mempelajari kode yang menggunakan detachedTree dan memastikan kode tersebut menghapus referensinya ke node saat tidak diperlukan lagi.

menyelidiki node kuning

Mengidentifikasi kebocoran memori heap JS dengan Linimasa Alokasi

Allocation Timeline adalah alat lain yang bisa membantu Anda melacak kebocoran memori di heap JS.

Untuk mendemonstrasikan Linimasa Alokasi, pertimbangkan kode berikut:

var x = [];

function grow() {
  x.push(new Array(1000000).join('x'));
}

document.getElementById('grow').addEventListener('click', grow);

Setiap kali tombol yang dirujuk dalam kode dikirim, string satu juta karakter akan ditambahkan ke array x.

Untuk merekam Allocation Timeline, buka DevTools, masuk ke panel Profiles, pilih tombol pilihan Record Allocation Timeline, tekan tombol Start, lakukan tindakan yang Anda curiga menyebabkan kebocoran memori, lalu tekan tombol stop recording (tombol berhenti merekam) setelah selesai.

Saat merekam, perhatikan apakah ada panel biru yang muncul di Linimasa Alokasi, seperti pada screenshot di bawah.

alokasi baru

Batang biru tersebut menunjukkan alokasi memori baru. Alokasi memori baru tersebut adalah kandidat untuk kebocoran memori. Anda dapat memperbesar panel untuk memfilter panel Konstruktor agar hanya menampilkan objek yang dialokasikan selama jangka waktu yang ditentukan.

linimasa alokasi yang diperbesar

Luaskan objek lalu klik nilainya untuk melihat detail selengkapnya tentangnya di panel Object. Misalnya, dalam screenshot di bawah, dengan melihat detail objek yang baru dialokasikan, Anda dapat melihat bahwa objek tersebut telah dialokasikan ke variabel x dalam cakupan Window.

detail objek

Menyelidiki alokasi memori berdasarkan fungsi

Gunakan jenis Allocation Sampling di panel Memory untuk melihat alokasi memori berdasarkan fungsi JavaScript.

Profiler Alokasi Rekaman

  1. Pilih tombol pilihan Allocation Sampling. Jika ada pekerja di halaman, Anda dapat memilihnya sebagai target pembuatan profil menggunakan menu dropdown di samping tombol Start.
  2. Tekan tombol Start.
  3. Lakukan tindakan pada halaman yang ingin Anda selidiki.
  4. Tekan tombol Stop setelah Anda menyelesaikan semua tindakan.

DevTools menampilkan perincian alokasi memori berdasarkan fungsi. Tampilan default adalah Heavy (Bottom Up), yang menampilkan fungsi yang mengalokasikan memori paling banyak di bagian atas.

Profil alokasi

Mengidentifikasi pembersihan sampah memori yang sering

Jika halaman Anda sering dijeda, Anda mungkin mengalami masalah pembersihan sampah memori.

Anda dapat menggunakan Pengelola Tugas Chrome atau perekaman memori Linimasa untuk menemukan pembersihan sampah memori yang sering dilakukan. Dalam Task Manager, nilai Memory atau JavaScript Memory yang sering naik dan turun menunjukkan pembersihan sampah memori yang sering. Dalam rekaman Linimasa, grafik heap JS atau jumlah node yang sering naik dan turun menunjukkan pembersihan sampah memori yang sering.

Setelah mengidentifikasi masalahnya, Anda dapat menggunakan perekaman Linimasa Alokasi untuk mengetahui tempat memori dialokasikan dan fungsi mana yang menyebabkan alokasi tersebut.