Merekam snapshot heap

Meggin Kearney
Meggin Kearney
Sofia Emelianova
Sofia Emelianova

Pelajari cara merekam snapshot heap dengan Memori > Profil > Snapshot heap dan menemukan kebocoran memori.

Profiler heap menampilkan distribusi memori berdasarkan objek JavaScript halaman Anda dan node DOM terkait. Gunakan alat ini untuk mengambil snapshot heap JS, menganalisis grafik memori, membandingkan snapshot, dan menemukan kebocoran memori. Untuk informasi selengkapnya, lihat Hierarki retensi objek.

Jepret

Untuk mengambil snapshot heap:

  1. Di halaman yang ingin Anda buat profilnya, buka DevTools dan buka panel Memory.
  2. Pilih jenis pembuatan profil Snapshot heap , lalu pilih instance JavaScript VM, dan klik Take snapshot.

Jenis pembuatan profil yang dipilih dan instance JavaScript VM.

Saat panel Memory memuat dan mengurai snapshot, panel tersebut akan menampilkan ukuran total objek JavaScript yang dapat dijangkau di bawah judul snapshot di bagian HEAP SNAPSHOTS.

Ukuran total objek yang dapat dijangkau.

Snapshot hanya menampilkan objek dari grafik memori yang dapat dijangkau dari objek global. Mengambil snapshot selalu dimulai dengan pembersihan sampah memori.

Snapshot heap dari objek Item yang tersebar.

Menghapus snapshot

Untuk menghapus semua snapshot, klik Hapus semua profil:

Menghapus semua profil.

Lihat snapshot

Untuk memeriksa snapshot dari perspektif yang berbeda untuk tujuan yang berbeda, pilih salah satu tampilan dari menu drop-down di bagian atas:

Lihat Konten Tujuan
Ringkasan Objek yang dikelompokkan berdasarkan nama dan sumber konstruktor. Gunakan untuk menemukan objek dan penggunaan memorinya berdasarkan jenis. Berguna untuk melacak kebocoran DOM.
Perbandingan Perbedaan antara dua snapshot. Gunakan untuk membandingkan dua (atau beberapa) snapshot, sebelum dan sesudah operasi. Konfirmasi keberadaan dan penyebab kebocoran memori dengan memeriksa delta dalam memori yang dibebaskan dan jumlah referensi.
Pembatasan Konten heap Memberikan tampilan struktur objek yang lebih baik, dan membantu menganalisis objek yang direferensikan dalam namespace (jendela) global untuk menemukan apa yang membuatnya tetap ada. Gunakan untuk menganalisis penutupan dan mempelajari objek Anda di tingkat rendah.
Statistik Diagram lingkaran alokasi memori Lihat ukuran relatif bagian memori yang dialokasikan untuk kode, string, array JS, array berjenis, dan objek sistem.

Tampilan Ringkasan yang dipilih dari menu drop-down di bagian atas.

Tampilan ringkasan

Awalnya, snapshot heap akan terbuka di tampilan Ringkasan yang mencantumkan Konstruktor dalam kolom. Konstruktor diberi nama berdasarkan fungsi JavaScript yang membuat objek, nama objek biasa didasarkan pada properti yang dikandungnya, dan beberapa nama adalah entri khusus. Semua objek dikelompokkan menurut namanya terlebih dahulu, lalu menurut baris dalam file sumber asalnya, misalnya, source-file.js:line-number.

Anda dapat meluaskan konstruktor yang dikelompokkan untuk melihat objek yang dibuat instance-nya.

Tampilan Ringkasan dengan konstruktor yang diperluas.

Untuk memfilter konstruktor yang tidak relevan, ketik nama yang ingin Anda periksa di Filter class di bagian atas tampilan Ringkasan.

Angka di samping nama konstruktor menunjukkan jumlah total objek yang dibuat dengan konstruktor. Tampilan Ringkasan juga menampilkan kolom berikut:

  • Jarak menunjukkan jarak ke root menggunakan jalur sederhana terpendek dari node.
  • Ukuran dangkal menampilkan jumlah ukuran dangkal dari semua objek yang dibuat oleh konstruktor tertentu. Shallow size adalah ukuran memori yang disimpan oleh objek itu sendiri. Umumnya, array dan string memiliki ukuran dangkal yang lebih besar. Lihat juga Ukuran objek.
  • Retained size menunjukkan retained size maksimum di antara kumpulan objek yang sama. Retained size adalah ukuran memori yang dapat Anda bebaskan dengan menghapus objek dan membuat dependennya tidak dapat dijangkau lagi. Lihat juga Ukuran objek.

Saat Anda meluaskan konstruktor, tampilan Ringkasan akan menampilkan semua instance-nya. Setiap instance mendapatkan perincian ukuran dangkal dan yang dipertahankan di kolom yang sesuai. Angka setelah karakter @ adalah ID unik objek. Dengan begitu, Anda dapat membandingkan snapshot heap berdasarkan per objek.

Filter konstruktor

Tampilan Ringkasan memungkinkan Anda memfilter konstruktor berdasarkan kasus umum penggunaan memori yang tidak efisien.

Untuk menggunakan filter ini, pilih salah satu opsi berikut dari menu drop-down paling kanan di panel tindakan:

  • Semua objek: semua objek yang diambil oleh snapshot saat ini. Ditetapkan secara default.
  • Objek yang dialokasikan sebelum snapshot 1: objek yang dibuat dan tetap berada di memori sebelum snapshot pertama diambil.
  • Objek yang dialokasikan antara Snapshot 1 dan Snapshot 2: melihat perbedaan objek antara snapshot terbaru dan snapshot sebelumnya. Setiap snapshot baru akan menambahkan penambahan filter ini ke daftar drop-down.
  • String duplikat: nilai string yang telah disimpan beberapa kali dalam memori.
  • Objek yang dipertahankan oleh node terpisah: objek yang tetap aktif karena node DOM terpisah mereferensikannya.
  • Objek yang dipertahankan oleh konsol DevTools: objek yang disimpan dalam memori karena dievaluasi atau berinteraksi melalui konsol DevTools.

Entri khusus di Ringkasan

Selain mengelompokkan menurut konstruktor, tampilan Ringkasan juga mengelompokkan objek menurut:

  • Fungsi bawaan seperti Array atau Object.
  • Elemen HTML yang dikelompokkan menurut tagnya, misalnya, <div>, <a>, <img>, dan lainnya.
  • Fungsi yang Anda tentukan dalam kode.
  • Kategori khusus yang tidak didasarkan pada konstruktor.

Entri konstruktor.

(array)

Kategori ini mencakup berbagai objek seperti array internal yang tidak langsung sesuai dengan objek yang terlihat di JavaScript.

Misalnya, konten objek Array JavaScript disimpan dalam objek internal sekunder bernama (object elements)[], untuk mempermudah pengubahan ukuran. Demikian pula, properti bernama dalam objek JavaScript sering disimpan dalam objek internal sekunder bernama (object properties)[] yang juga tercantum dalam kategori (array).

(compiled code)

Kategori ini mencakup data internal yang diperlukan V8 agar dapat menjalankan fungsi yang ditentukan oleh JavaScript atau WebAssembly. Setiap fungsi dapat direpresentasikan dengan berbagai cara, mulai dari kecil dan lambat hingga besar dan cepat.

V8 secara otomatis mengelola penggunaan memori dalam kategori ini. Jika fungsi berjalan berkali-kali, V8 akan menggunakan lebih banyak memori untuk fungsi tersebut sehingga dapat berjalan lebih cepat. Jika fungsi belum berjalan dalam waktu yang lama, V8 dapat menghapus data internal untuk fungsi tersebut.

(concatenated string)

Saat V8 menyambungkan dua string, seperti dengan operator + JavaScript, V8 dapat memilih untuk menampilkan hasilnya secara internal sebagai "string yang digabungkan" yang juga dikenal sebagai struktur data Rope.

Daripada menyalin semua karakter dari dua string sumber ke string baru, V8 mengalokasikan objek kecil dengan kolom internal yang disebut first dan second, yang mengarah ke dua string sumber. Hal ini memungkinkan V8 menghemat waktu dan memori. Dari perspektif kode JavaScript, ini hanyalah string normal, dan berperilaku seperti string lainnya.

InternalNode

Kategori ini mewakili objek yang dialokasikan di luar V8, seperti objek C++ yang ditentukan oleh Blink.

Untuk melihat nama class C++, gunakan Chrome untuk Pengujian dan lakukan hal berikut:

  1. Buka DevTools dan aktifkan Settings > Experiments > Show option to expose internals in heap snapshots.
  2. Buka panel Memory, pilih Heap snapshot, dan aktifkan Expose internals (includes additional implementation-specific details).
  3. Rekonstruksi masalah yang menyebabkan InternalNode mempertahankan banyak memori.
  4. Ambil snapshot heap. Dalam snapshot ini, objek memiliki nama class C++, bukan InternalNode.
(object shape)

Seperti yang dijelaskan dalam Fast Properties in V8, V8 melacak class tersembunyi (atau bentuk) sehingga beberapa objek dengan properti yang sama dalam urutan yang sama dapat direpresentasikan secara efisien. Kategori ini berisi class tersembunyi tersebut, yang disebut system / Map (tidak terkait dengan JavaScript Map), dan data terkait.

(sliced string)

Saat V8 perlu mengambil substring, seperti saat kode JavaScript memanggil String.prototype.substring(), V8 dapat memilih untuk mengalokasikan objek string yang diiris, bukan menyalin semua karakter yang relevan dari string asli. Objek baru ini berisi pointer ke string asli dan menjelaskan rentang karakter dari string asli yang akan digunakan.

Dari perspektif kode JavaScript, ini hanyalah string normal, dan berperilaku seperti string lainnya. Jika string yang dipotong menyimpan banyak memori, program mungkin telah memicu Masalah 2869 dan mungkin akan mendapatkan manfaat dengan mengambil langkah-langkah yang disengaja untuk "meratakan" string yang dipotong.

system / Context

Objek internal jenis system / Context berisi variabel lokal dari penutupan—cakupan JavaScript yang dapat diakses oleh fungsi bertingkat.

Setiap instance fungsi berisi pointer internal ke Context tempat fungsi dieksekusi, sehingga dapat mengakses variabel tersebut. Meskipun objek Context tidak langsung terlihat dari JavaScript, Anda memiliki kontrol langsung atas objek tersebut.

(system)

Kategori ini berisi berbagai objek internal yang belum (belum) dikategorikan dengan cara yang lebih bermakna.

Tampilan perbandingan

Tampilan Perbandingan memungkinkan Anda menemukan objek yang bocor dengan membandingkan beberapa snapshot satu sama lain. Misalnya, melakukan tindakan dan membatalkan tindakan tersebut, seperti membuka dokumen dan menutupnya, tidak boleh meninggalkan objek tambahan.

Untuk memverifikasi bahwa operasi tertentu tidak menyebabkan kebocoran:

  1. Ambil snapshot heap sebelum melakukan operasi.
  2. Melakukan operasi. Artinya, berinteraksilah dengan halaman dengan cara yang menurut Anda mungkin menyebabkan kebocoran.
  3. Lakukan operasi terbalik. Artinya, lakukan interaksi yang berlawanan dan ulangi beberapa kali.
  4. Ambil snapshot heap kedua dan ubah tampilannya menjadi Perbandingan, yang membandingkannya dengan Snapshot 1.

Tampilan Perbandingan menunjukkan perbedaan antara dua snapshot. Saat memperluas entri total, instance objek yang ditambahkan dan dihapus akan ditampilkan:

Dibandingkan dengan Snapshot 1.

Tampilan pembatasan

Tampilan Pembatasan adalah "tampilan dari atas" struktur objek aplikasi Anda. Dengan ini, Anda dapat melihat ke dalam penutupan fungsi, mengamati objek internal VM yang bersama-sama membentuk objek JavaScript, dan memahami jumlah memori yang digunakan aplikasi Anda pada tingkat yang sangat rendah.

Tampilan ini menyediakan beberapa titik entri:

  • Objek DOMWindow. Objek global untuk kode JavaScript.
  • Root GC. Root GC yang digunakan oleh pengumpulan sampah VM. Root GC dapat terdiri dari peta objek bawaan, tabel simbol, stack thread VM, cache kompilasi, cakupan handle, dan handle global.
  • Objek native. Objek browser "didorong" ke dalam virtual machine JavaScript untuk memungkinkan otomatisasi, misalnya, node DOM dan aturan CSS.

Tampilan Pembatasan.

Bagian Penahan

Bagian Retainers di bagian bawah panel Memory menampilkan objek yang mengarah ke objek yang dipilih dalam tampilan. Panel Memory memperbarui bagian Retainers saat Anda memilih objek lain di tampilan apa pun kecuali Statistics.

Bagian Penahan.

Dalam contoh ini, string yang dipilih dipertahankan oleh properti x dari instance Item.

Mengabaikan retainer

Anda dapat menyembunyikan penahan untuk mengetahui apakah objek lain mempertahankan objek yang dipilih. Dengan opsi ini, Anda tidak perlu menghapus penahan ini dari kode terlebih dahulu, lalu mengambil kembali snapshot heap.

Opsi &#39;Abaikan retensi ini&#39; di menu drop-down.

Untuk menyembunyikan penahan, klik kanan dan pilih Abaikan penahan ini. Retainer yang diabaikan ditandai sebagai ignored di kolom Jarak. Untuk berhenti mengabaikan semua retensi, klik Restore ignored retainers di panel tindakan di bagian atas.

Menemukan objek tertentu

Untuk menemukan objek dalam heap yang dikumpulkan, Anda dapat menelusuri menggunakan Ctrl + F dan memasukkan ID objek.

Memberi nama fungsi untuk membedakan penutupan

Memberi nama fungsi akan sangat membantu sehingga Anda dapat membedakan antara penutupan dalam snapshot.

Misalnya, kode berikut tidak menggunakan fungsi bernama:

function createLargeClosure() {
  var largeStr = new Array(1000000).join('x');

  var lC = function() { // this is NOT a named function
    return largeStr;
  };

  return lC;
}

Sementara contoh ini:

function createLargeClosure() {
  var largeStr = new Array(1000000).join('x');

  var lC = function lC() { // this IS a named function
    return largeStr;
  };

  return lC;
}

Fungsi bernama dalam penutupan.

Menemukan kebocoran DOM

Profiler heap memiliki kemampuan untuk mencerminkan dependensi dua arah antara objek native browser (node DOM dan aturan CSS) dan objek JavaScript. Hal ini membantu menemukan kebocoran yang tidak terlihat yang terjadi karena subtree DOM yang terlepas dan terlupakan.

Kebocoran DOM bisa lebih besar dari yang Anda kira. Perhatikan contoh berikut. Kapan sampah #tree dikumpulkan?

  var select = document.querySelector;
  var treeRef = select("#tree");
  var leafRef = select("#leaf");
  var body = select("body");

  body.removeChild(treeRef);

  //#tree can't be GC yet due to treeRef
  treeRef = null;

  //#tree can't be GC yet due to indirect
  //reference from leafRef

  leafRef = null;
  //#NOW #tree can be garbage collected

#leaf mempertahankan referensi ke induknya (parentNode) dan secara rekursif hingga #tree, sehingga hanya saat leafRef dihapus, hierarki seluruh di bawah #tree menjadi kandidat untuk GC.

Sub-pohon DOM