Memperbaiki masalah memori

Kayce Basques
Kayce Basques

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

Ringkasan

  • Cari tahu jumlah memori yang digunakan halaman Anda dengan Pengelola Tugas Chrome.
  • Visualisasikan penggunaan memori dari waktu ke waktu dengan rekaman Linimasa.
  • Mengidentifikasi hierarki DOM terpisah (penyebab umum kebocoran memori) dengan Cuplikan Heap.
  • Cari tahu kapan memori baru dialokasikan di heap JS Anda dengan rekaman Linimasa Alokasi.
  • Mengidentifikasi elemen terlepas yang dipertahankan oleh referensi JavaScript.

Ringkasan

Dalam semangat model performa RAIL, fokus upaya performa Anda haruslah pengguna.

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

  • Performa halaman semakin memburuk seiring waktu. Hal ini mungkin merupakan gejala kebocoran memori. Kebocoran memori adalah saat bug di halaman menyebabkan halaman menggunakan lebih banyak memori seiring waktu.
  • Performa halaman selalu buruk. Hal ini mungkin merupakan gejala bloat memori. Pembengkakan memori terjadi saat halaman menggunakan lebih banyak memori daripada yang diperlukan untuk kecepatan halaman yang optimal.
  • Performa halaman tertunda atau sering kali tampak dijeda. Hal ini mungkin merupakan gejala dari pembersihan sampah memori yang sering. Pembersihan sampah memori adalah saat browser mengklaim kembali memori. Browser menentukan kapan hal ini terjadi. Selama pengumpulan, semua eksekusi skrip dijeda. Jadi, jika browser banyak melakukan pembersihan sampah memori, eksekusi skrip akan sering dijeda.

Pembengkakan memori: seberapa banyak yang dianggap "terlalu banyak"?

Kebocoran memori mudah didefinisikan. Jika situs semakin banyak menggunakan memori, berarti Anda mengalami kebocoran. Namun, pembengkakan memori agak lebih sulit untuk diidentifikasi. Apa yang memenuhi syarat sebagai "menggunakan terlalu banyak memori"?

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

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

Memantau penggunaan memori secara real-time dengan Pengelola Tugas Chrome

Gunakan Pengelola Tugas Chrome sebagai titik awal untuk menyelidiki masalah memori. Pengelola Tugas 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 Pengelola Tugas.

  2. Klik kanan header tabel Pengelola Tugas dan aktifkan Memori JavaScript.

    Mengaktifkan memori JS di header Pengelola tugas.

Kedua kolom ini memberi tahu Anda berbagai hal tentang cara halaman menggunakan memori:

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

    Pengelola Tugas dengan header memori JavaScript diaktifkan.

Memvisualisasikan kebocoran memori dengan rekaman Performance

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

  1. Buka panel Performa di DevTools.
  2. Centang kotak Memory.
  3. Membuat rekaman.

Untuk menunjukkan 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 ditambahkan ke isi dokumen, dan string satu juta karakter x dikirim ke array x. Menjalankan kode ini akan menghasilkan rekaman Linimasa seperti screenshot berikut:

Contoh pertumbuhan sederhana.

Pertama, penjelasan tentang antarmuka pengguna. Grafik HEAP di panel Overview (di bawah NET) mewakili heap JS. Di bawah panel Overview terdapat 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 tersebut cocok dengan kode. Jumlah node meningkat dalam langkah-langkah diskret. Anda dapat mengasumsikan bahwa setiap peningkatan jumlah node adalah panggilan ke grow(). Grafik heap JS (grafik biru) tidak sesederhana itu. Sesuai dengan praktik terbaik, penurunan pertama sebenarnya adalah pembersihan sampah memori paksa (dicapai dengan menekan tombol collect garbage). Saat perekaman berlangsung, Anda dapat melihat bahwa ukuran heap JS melonjak. Hal ini wajar dan sudah diperkirakan: kode JavaScript membuat node DOM pada setiap klik tombol dan melakukan banyak pekerjaan saat membuat string satu juta karakter. Hal penting di sini adalah fakta bahwa heap JS berakhir lebih tinggi daripada saat dimulai ("awal" di sini adalah titik setelah pembersihan sampah memori paksa). Di dunia nyata, jika Anda melihat pola peningkatan ukuran heap JS atau ukuran node, hal ini berpotensi berarti kebocoran memori.

Menemukan kebocoran memori hierarki DOM yang terlepas dengan Cuplikan Heap

Node DOM hanya dapat dibersihkan dari sampah memori jika tidak ada referensi ke node tersebut dari hierarki DOM halaman atau kode JavaScript. Node dikatakan "terlepas" jika dihapus dari hierarki DOM, tetapi beberapa JavaScript masih mereferensikannya. Node DOM terpisah 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);

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

Cuplikan heap adalah salah satu cara untuk mengidentifikasi node yang terlepas. Seperti namanya, cuplikan heap menunjukkan kepada Anda cara memori didistribusikan di antara objek JS dan node DOM halaman Anda pada saat cuplikan diambil.

Untuk membuat snapshot, buka DevTools dan buka panel Memori, pilih tombol pilihan Cuplikan heap, lalu tekan tombol Take snapshot.

Tombol pilihan Ambil cuplikan heap dipilih.

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

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

Memfilter node yang terlepas.

Luaskan tanda sisipan untuk menyelidiki 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 khusus ini, Anda akan mempelajari kode yang menggunakan detachedTree dan memastikan bahwa kode tersebut menghapus referensinya ke node saat tidak lagi diperlukan.

Menyelidiki node yang terlepas.

Mengidentifikasi kebocoran memori heap JS dengan Linimasa Alokasi

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

Untuk menunjukkan 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 akan ditambahkan ke array x.

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

Saat Anda merekam, perhatikan apakah ada panel biru yang muncul di Allocation Timeline, seperti dalam screenshot berikut.

Alokasi baru di linimasa performa.

Batang biru tersebut mewakili alokasi memori baru. Alokasi memori baru tersebut adalah kandidat untuk kebocoran memori. Anda dapat memperbesar batang 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 tentang objek tersebut di panel Object. Misalnya, pada 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 array string.

Menyelidiki alokasi memori berdasarkan fungsi

Gunakan jenis profil Sampling alokasi di panel Memori untuk melihat alokasi memori menurut fungsi JavaScript.

Profiler pengambilan sampel alokasi di panel Memori.

  1. Pilih tombol pilihan Allocation sampling. Jika ada worker 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 selidiki.
  4. Tekan tombol Berhenti 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.

Halaman hasil profil alokasi.

Mengidentifikasi objek yang dipertahankan oleh referensi JS

Profil Elemen terlepas menampilkan elemen terlepas yang tetap ada karena direferensikan oleh kode JavaScript.

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

Contoh profil elemen terpisah.

Mendeteksi pembersihan sampah memori yang sering terjadi

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

Anda dapat menggunakan Pengelola Tugas Chrome atau rekaman memori Linimasa untuk menemukan pembersihan sampah memori yang sering terjadi. Di Task Manager, 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 terjadi.

Setelah mengidentifikasi masalah, Anda dapat menggunakan rekaman Allocation Timeline untuk mengetahui di mana memori dialokasikan dan fungsi mana yang menyebabkan alokasi tersebut.