Memperbaiki masalah memori

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

Ringkasan

  • Cari tahu berapa banyak memori yang digunakan oleh halaman Anda dengan Task Manager pada Chrome.
  • Visualisasikan penggunaan memori seiring waktu dengan perekaman Timeline.
  • Mengidentifikasi hierarki DOM yang terlepas (penyebab umum kebocoran memori) dengan Cuplikan Heap.
  • Mengetahui cara memori baru dialokasikan di heap JS Anda dengan perekaman Allocation Timeline.
  • Identifikasi elemen terpisah yang dipertahankan oleh referensi JavaScript.

Ringkasan

Dengan prinsip model performa RAIL, fokus upaya peningkatan performa Anda harus pengguna.

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

  • Kinerja halaman secara progresif menjadi buruk seiring waktu. Hal ini mungkin merupakan gejala kebocoran memori. Kebocoran memori terjadi saat bug di halaman menyebabkan halaman secara progresif menggunakan lebih banyak memori seiring waktu.
  • Kinerja halaman terus-menerus buruk. Hal ini mungkin merupakan gejala penggelembungan memori. Penggelembungan memori terjadi saat halaman menggunakan lebih banyak memori daripada yang diperlukan untuk kecepatan halaman yang optimal.
  • Kinerja halaman lambat atau tampak sering dijeda. Hal ini mungkin merupakan gejala pengumpulan sampah yang sering. Pengumpulan sampah adalah saat browser mengklaim kembali memori. Browser menentukan kapan hal ini terjadi. Selama proses pengumpulan, semua eksekusi skrip akan dijeda. Jadi, jika browser sering melakukan pembersihan sampah, eksekusi skrip akan sering dijeda.

Penggelembungan memori: di mana batasnya?

Kebocoran memori mudah didefinisikan. Jika situs secara progresif menggunakan lebih banyak memori, berarti Anda mengalami kebocoran. Namun, penggelembungan memori sedikit lebih sulit ditemukan penyebabnya. Penggunaan memori sebesar apa yang dianggap "terlalu banyak"?

Tidak ada angka yang pasti, karena perangkat dan browser yang berbeda memiliki kemampuan yang berbeda. Laman yang sama yang berjalan lancar di smartphone kelas atas mungkin mengalami error di smartphone kelas bawah.

Kuncinya adalah menggunakan model RAIL dan berfokus pada pengguna. Cari tahu perangkat apa yang paling banyak digunakan oleh pengguna, lalu uji halaman Anda di perangkat tersebut. Jika pengalamannya buruk secara konsisten, halaman mungkin melampaui kemampuan memori perangkat tersebut.

Memantau penggunaan memori secara realtime dengan Task Manager pada Chrome

Gunakan Task Manager pada Chrome sebagai titik awal penyelidikan masalah memori. Task Manager adalah monitor real-time yang memberi tahu Anda jumlah memori yang digunakan halaman.

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

    Membuka Task Manager.

  2. Klik kanan header tabel Task Manager dan aktifkan JavaScript memory.

    Mengaktifkan memori JS di header Task manager.

Dua kolom ini menyampaikan berbagai informasi tentang cara laman menggunakan memori:

  • Kolom Jejak memori mewakili memori OS. Node DOM disimpan di memori OS. Jika nilai ini meningkat, node DOM sedang dibuat.
  • Kolom JavaScript Memory mewakili heap JS. Kolom ini berisi dua nilai. Nilai yang Anda minati adalah nomor langsung (angka dalam tanda kurung). Angka langsung menunjukkan jumlah memori yang digunakan oleh objek yang dapat dijangkau di halaman Anda. Jika jumlah ini meningkat, artinya objek baru sedang dibuat, atau objek yang ada meningkat.

    Task Manager dengan header memori JavaScript diaktifkan.

Memvisualkan kebocoran memori dengan perekaman Performa

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

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

Untuk mendemonstrasikan perekaman memori Performa, pertimbangkan kode berikut:

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 direferensikan dalam kode ditekan, sepuluh ribu node div akan ditambahkan ke isi dokumen, dan string satu juta karakter x akan dimasukkan ke dalam array x. Menjalankan kode ini akan menghasilkan rekaman Linimasa seperti screenshot berikut:

Contoh pertumbuhan sederhana.

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

Sekarang, analisis kode dibandingkan dengan screenshot. Jika Anda melihat penghitung node (grafik hijau), Anda dapat melihat bahwa jumlahnya cocok dengan kode. Jumlah node meningkat dalam langkah terpisah. Anda dapat mengasumsikan bahwa setiap peningkatan jumlah node adalah panggilan ke grow(). Grafik heap JS (grafik biru) tidak sama jelasnya. Sesuai dengan praktik terbaik, penurunan pertama sebenarnya adalah pengumpulan sampah paksa (dicapai dengan menekan tombol collect garbage). Seiring berjalannya perekaman, Anda dapat melihat bahwa ukuran heap JS meningkat drastis. Hal ini wajar dan dapat diduga: kode JavaScript membuat node DOM pada setiap klik tombol dan melakukan banyak pekerjaan saat membuat string yang berjumlah satu juta karakter. Intinya, fakta bahwa heap JS berakhir lebih tinggi dari saat dimulai ("awal" di sini adalah titik setelah pengumpulan sampah paksa). Dalam kondisi nyata, jika Anda melihat pola meningkatnya ukuran heap JS atau ukuran node, ini berpotensi berarti kebocoran memori.

Menemukan kebocoran memori hierarki DOM yang terlepas dengan Cuplikan Heap

Node DOM hanya dapat dikumpulkan sampahnya jika tidak ada referensi kepadanya dari kode JavaScript atau pohon DOM halaman. Simpul dikatakan "terlepas" saat dihapus dari hierarki DOM, tetapi beberapa JavaScript masih mereferensikannya. Node DOM yang terlepas adalah penyebab umum kebocoran memori. Bagian ini mengajarkan cara menggunakan profiler heap DevTools untuk mengidentifikasi node yang terlepas.

Berikut adalah contoh sederhana node 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);

Mengeklik 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 dilepaskan.

Cuplikan heap adalah salah satu cara untuk mengidentifikasi node yang terlepas. Seperti namanya, snapshot heap menunjukkan cara memori didistribusikan di antara objek JS dan node DOM halaman pada waktu cuplikan dibuat.

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

Tombol pilihan Ambil snapshot heap dipilih.

Cuplikan mungkin membutuhkan waktu beberapa saat untuk diproses dan dimuat. Setelah selesai, pilih dari panel sebelah kiri (bernama Snapshot heap).

Ketikkan Detached di kotak input Class filter untuk menelusuri hierarki DOM yang terlepas.

Memfilter node yang terlepas.

Luaskan karat untuk menginvestigasi hierarki yang terlepas.

Menyelidiki hierarki yang terlepas.

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

Menyelidiki node yang terlepas.

Mengidentifikasi kebocoran memori heap JS dengan Allocation Timeline

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

Untuk mendemonstrasikan Allocation Timeline, pertimbangkan kode berikut:

var x = [];

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

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

Setiap kali tombol yang direferensikan dalam kode ditekan, string satu juta karakter ditambahkan ke array x.

Untuk merekam Linimasa Alokasi, buka DevTools, buka panel Memory, pilih tombol pilihan Allocations on timeline, tekan tombol Record, lakukan tindakan yang Anda curigai menyebabkan kebocoran memori, lalu tekan tombol Stop recording setelah selesai.

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

Alokasi baru di linimasa performa.

Bilah biru tersebut menggambarkan alokasi memori baru. Alokasi memori baru tersebut adalah kandidat untuk kebocoran memori. Anda dapat memperbesar suatu bilah untuk memfilter panel Constructor agar hanya menampilkan objek yang dialokasikan selama jangka waktu yang ditentukan.

Linimasa alokasi yang diperbesar.

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

Detail objek array string.

Menyelidiki alokasi memori berdasarkan fungsi

Gunakan jenis profil Pengambilan sampel alokasi di panel Memori untuk melihat alokasi memori berdasarkan fungsi JavaScript.

Profiler sampling alokasi di panel Memori.

  1. Pilih tombol pilihan Pengambilan sampel alokasi. Jika ada pekerja di halaman, Anda dapat memilihnya sebagai target pembuatan profil dari jendela Select JavaScript VM instance.
  2. Tekan tombol Start.
  3. Lakukan tindakan di halaman yang ingin Anda periksa.
  4. Tekan tombol Stop setelah Anda menyelesaikan semua tindakan.

DevTools menampilkan perincian alokasi memori menurut fungsi. Tampilan defaultnya adalah Heavy (Bottom Up), yang menampilkan fungsi yang mengalokasikan memori terbanyak di bagian atas.

Halaman hasil profil alokasi.

Mengidentifikasi objek yang dipertahankan oleh referensi JS

Profil Elemen terpisah menampilkan elemen terpisah yang tetap ada karena dirujuk oleh kode JavaScript.

Rekam profil Elemen terpisah untuk melihat node HTML dan jumlah node yang tepat.

Contoh profil elemen terpisah.

Menemukan pengumpulan sampah yang sering

Jika halaman Anda tampak sering dijeda, mungkin ada masalah pengumpulan sampah.

Anda dapat menggunakan Task Manager Chrome atau perekaman memori Timeline untuk menemukan pengumpulan sampah yang sering. Di Task Manager, nilai Memory atau JavaScript Memory yang sering naik dan turun menunjukkan pengumpulan sampah yang sering. Dalam rekaman Timeline, grafik heap JS atau jumlah simpul yang sering naik dan turun menunjukkan pengumpulan sampah yang sering.

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