Memperbaiki masalah memori

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.

Ringkasan

  • Ketahui berapa banyak memori yang saat ini digunakan halaman Anda dengan Pengelola Tugas Chrome.
  • Visualisasikan penggunaan memori dari waktu ke waktu dengan perekaman Linimasa.
  • Mengidentifikasi hierarki DOM yang terlepas (penyebab umum kebocoran memori) dengan Cuplikan Heap.
  • Cari tahu kapan memori baru dialokasikan di heap JS Anda dengan perekaman Allocation Linimasa.

Ringkasan

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

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

  • Performa halaman secara bertahap menjadi buruk seiring waktu. Hal ini mungkin gejala kebocoran memori. Kebocoran memori terjadi saat bug di halaman menyebabkan halaman menggunakan lebih banyak memori secara bertahap seiring waktu.
  • Performa halaman terus-menerus buruk. Ini mungkin merupakan gejala kegembungan memori. Penggelembungan memori terjadi saat halaman menggunakan memori lebih besar dari yang diperlukan untuk mengoptimalkan kecepatan halaman.
  • Performa halaman tertunda atau tampak sering dijeda. Hal ini mungkin merupakan gejala seringnya pembersihan sampah memori. Pembersihan sampah memori adalah saat browser mengklaim kembali memori. Browser akan menentukan kapan hal ini terjadi. Selama proses pengumpulan, semua eksekusi skrip akan dijeda. Jadi, jika browser sering membersihkan sampah memori, eksekusi skrip akan sering dijeda.

Penggembungan memori: “terlalu banyak”?

Kebocoran memori mudah ditentukan. Jika sebuah situs secara bertahap menggunakan lebih banyak memori, berarti ada kebocoran. Namun, penggelembungan memori agak lebih sulit untuk dijabarkan. Apa yang memenuhi syarat sebagai "menggunakan terlalu banyak memori"?

Tidak ada angka yang pasti di sini, karena perangkat dan browser yang berbeda memiliki kemampuan yang berbeda. Halaman yang sama yang berjalan mulus di ponsel pintar kelas atas bisa saja mogok di ponsel pintar kelas bawah.

Kuncinya di sini adalah menggunakan model RAIL dan fokus pada pengguna Anda. Cari tahu perangkat apa yang populer di kalangan pengguna, lalu uji halaman Anda di perangkat tersebut. Jika pengalaman pengguna selalu buruk, halaman mungkin melampaui kemampuan memori perangkat tersebut.

Memantau penggunaan memori secara realtime dengan Task Manager pada Chrome

Gunakan Pengelola Tugas Chrome sebagai titik awal untuk penyelidikan masalah memori Anda. Task Manager adalah monitor realtime yang memberi tahu Anda berapa banyak memori yang saat ini digunakan halaman.

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

    Membuka Pengelola Tugas

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

    Mengaktifkan memori JS

Kedua kolom ini menunjukkan berbagai hal tentang cara halaman menggunakan memori:

  • Kolom Memori mewakili memori native. Node DOM disimpan di memori native. Jika nilai ini meningkat, node DOM akan dibuat.
  • Kolom Memori JavaScript mewakili heap JS. Kolom ini berisi dua nilai. Nilai yang Anda minati adalah angka aktual (angka dalam tanda kurung). Angka aktif menunjukkan banyaknya 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 lainnya 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 akan ditambahkan ke isi dokumen, dan string yang terdiri dari satu juta karakter x didorong 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 Counter. Di sini, Anda dapat melihat penggunaan memori yang dikelompokkan berdasarkan 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 screenshot. Jika melihat penghitung node (grafik hijau), Anda dapat melihat bahwa penghitung node tersebut cocok dengan kode. Jumlah {i>node<i} meningkat secara terpisah. 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 paksa (yang dilakukan dengan menekan tombol kumpulkan sampah). Selama perekaman berlangsung, Anda dapat melihat bahwa ukuran heap JS melonjak. Hal ini wajar dan wajar: kode JavaScript membuat node DOM pada setiap klik tombol dan melakukan banyak pekerjaan saat membuat string yang berisi satu juta karakter. Kuncinya di sini adalah fakta bahwa heap JS berakhir lebih tinggi daripada dimulainya ("awal" di sini adalah titik setelah pembersihan sampah memori paksa). Di dunia nyata, jika Anda melihat pola peningkatan ukuran heap JS atau ukuran node ini, kemungkinan itu berarti kebocoran memori.

Menemukan kebocoran memori hierarki DOM yang terlepas dengan Heap Snapshots

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

Berikut 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);

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 dilepas.

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 pada saat snapshot tersebut.

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

ambil snapshot heap

Mungkin perlu waktu beberapa saat untuk memproses dan memuat snapshot. Setelah selesai, pilih dari panel kiri (bernama HEAP SNAPSHOTS).

Ketikkan Detached di kotak teks Filter kelas untuk menelusuri hierarki DOM yang terlepas.

penyaringan untuk simpul yang terlepas

Luaskan karat untuk menyelidiki pohon yang terlepas.

menyelidiki pohon yang terlepas

Node yang ditandai dengan warna kuning memiliki referensi langsung dari kode JavaScript. Node yang ditandai dengan warna merah tidak memiliki referensi langsung. Simpul hanya hidup karena merupakan bagian dari pohon node kuning. Secara umum, Anda ingin berfokus pada node kuning. Perbaiki kode Anda sehingga node kuning tidak aktif lebih lama dari yang diperlukan, dan Anda juga dapat 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 merujuknya. Misalnya, dalam screenshot di bawah, Anda dapat melihat bahwa variabel detachedTree merujuk ke node. Untuk memperbaiki kebocoran memori ini, Anda akan mempelajari kode yang menggunakan detachedTree dan memastikan kode tersebut menghapus referensinya ke node saat tidak diperlukan lagi.

menyelidiki {i>node<i} kuning

Mengidentifikasi kebocoran memori heap JS dengan Allocation Linimasa

Allocation Linimasa 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 direferensikan dalam kode ditekan, string berisi satu juta karakter akan ditambahkan ke array x.

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

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

alokasi baru

Bilah biru tersebut merepresentasikan alokasi memori baru. Alokasi memori baru tersebut berpotensi mengalami kebocoran memori. Anda dapat memperbesar batang untuk memfilter panel Konstruktor 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 Object. Misalnya, dalam screenshot di bawah, dengan melihat detail objek yang baru dialokasikan, Anda akan dapat melihat bahwa objek tersebut dialokasikan ke variabel x dalam cakupan Window.

detail objek

Menginvestigasi alokasi memori berdasarkan fungsi

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

Rekam Profiler Alokasi

  1. Pilih tombol pilihan Allocation Sampling. Jika ada worker di halaman tersebut, 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 defaultnya adalah Heavy (Bottom Up), yang menampilkan fungsi yang mengalokasikan memori terbanyak di bagian atas.

Profil alokasi

Menemukan pembersihan sampah memori yang sering dilakukan

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

Anda dapat menggunakan Pengelola Tugas Chrome atau perekaman memori Linimasa untuk menemukan pembersihan sampah memori yang sering. Di Pengelola Tugas, nilai Memori atau Memori JavaScript 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 di mana memori dialokasikan dan fungsi mana yang menyebabkan alokasi tersebut.