Merekam snapshot heap

Meggin Kearney
Meggin Kearney
Sofia Emelianova
Sofia Emelianova

Pelajari cara merekam snapshot heap dengan Memori > Profil > Cuplikan heap dan temukan kebocoran memori.

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

Jepret

Untuk mengambil cuplikan heap:

  1. Di halaman yang ingin dibuat profilnya, buka DevTools dan buka panel Memory.
  2. Pilih jenis pembuatan profil Heap snapshot radio_button_checked, lalu pilih instance VM JavaScript, kemudian klik Take snapshot.

Jenis pembuatan profil dan instance VM JavaScript yang dipilih.

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

Ukuran total objek yang dapat dijangkau.

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

Snapshot heap dari objek Item yang tersebar.

Hapus snapshot

Untuk menghapus semua snapshot, klik blokir Hapus semua profil:

Hapus semua profil.

Lihat snapshot

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

Lihat Konten Tujuan
Ringkasan Objek yang dikelompokkan berdasarkan nama konstruktor. Gunakan alat ini untuk memburu objek dan penggunaan memorinya berdasarkan jenisnya. Berguna untuk melacak kebocoran DOM.
Perbandingan Perbedaan antara dua snapshot. Gunakan laporan ini untuk membandingkan dua snapshot (atau lebih), sebelum dan setelah operasi. Pastikan 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 di namespace (jendela) global untuk menemukan apa yang membuatnya tetap ada di sana. Gunakan alat ini untuk menganalisis penutupan dan mempelajari objek Anda di level rendah.
Statistik Diagram lingkaran alokasi memori Lihat ukuran realtif bagian memori yang dialokasikan untuk kode, string, array JS, array yang diketik, dan objek sistem.

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

Tampilan ringkasan

Awalnya, snapshot heap terbuka dalam tampilan Summary yang mencantumkan Konstruktor dalam kolom. Anda dapat memperluas konstruktor untuk melihat objek yang dibuat instance-nya.

Tampilan Summary dengan konstruktor yang diperluas.

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

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

  • Jarak menunjukkan jarak ke akar menggunakan jalur node sederhana terpendek.
  • Shallow size menunjukkan jumlah ukuran dangkal semua objek yang dibuat oleh konstruktor tertentu. {i>shallow size<i} adalah ukuran memori yang dimiliki oleh objek itu sendiri. Umumnya, array dan string memiliki ukuran dangkal yang lebih besar. Lihat juga Ukuran objek.
  • Retained size menampilkan ukuran yang dipertahankan maksimum di antara kumpulan objek yang sama. Retained size adalah ukuran memori yang dapat Anda bebaskan dengan menghapus objek dan membuat turunannya tidak lagi dapat dijangkau. Lihat juga Ukuran objek.

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

Entri khusus di Ringkasan

Selain mengelompokkan berdasarkan konstruktor, tampilan Summary juga mengelompokkan objek berdasarkan:

  • Fungsi bawaan seperti Array atau Object.
  • Fungsi yang Anda tetapkan dalam kode.
  • Kategori khusus yang tidak didasarkan pada konstruktor.

Entri konstruktor.

(array)

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

Misalnya, konten objek Array JavaScript disimpan dalam objek internal sekunder bernama (object elements)[], untuk memungkinkan pengubahan ukuran yang lebih mudah. 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 dalam berbagai cara, dari kecil dan lambat hingga besar dan cepat.

V8 mengelola penggunaan memori dalam kategori ini secara otomatis. Jika fungsi berjalan berkali-kali, V8 akan menggunakan lebih banyak memori untuk fungsi tersebut sehingga dapat berjalan lebih cepat. Jika suatu fungsi tidak berjalan beberapa saat, V8 dapat menghapus data internal untuk fungsi tersebut.

(concatenated string)

Saat V8 menyambungkan dua string, seperti operator + JavaScript, ia dapat memilih untuk mewakili hasilnya secara internal sebagai "string gabungan" yang juga dikenal sebagai struktur data Tali.

Daripada menyalin semua karakter dari dua string sumber ke dalam 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 for Testing dan lakukan hal berikut:

  1. Buka DevTools dan aktifkan setelan Settings > Experiments > kotak centang Tampilkan opsi untuk mengekspos internal dalam snapshot heap.
  2. Buka panel Memory, pilih radio_button_checked Heap snapshot, dan aktifkan check_box Perlihatkan internal (termasuk detail khusus implementasi tambahan).
  3. Reproduksi masalah yang menyebabkan InternalNode mempertahankan banyak memori.
  4. Ambil cuplikan heap. Dalam snapshot ini, objek memiliki nama class C++, bukan InternalNode.
(object shape)

Seperti yang dijelaskan dalam Properti Cepat di 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 kisaran karakter mana dari string asli yang akan digunakan.

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

system / Context

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

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

(system)

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

Tampilan perbandingan

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

Untuk memverifikasi bahwa operasi tertentu tidak membuat kebocoran:

  1. Ambil cuplikan heap sebelum menjalankan operasi.
  2. Melakukan operasi. Artinya, berinteraksi dengan halaman yang menurut Anda dapat menyebabkan kebocoran.
  3. Lakukan operasi kebalikan. Artinya, lakukan interaksi yang berlawanan dan ulangi beberapa kali.
  4. Ambil snapshot heap kedua dan ubah tampilannya ke Comparison, bandingkan dengan Snapshot 1.

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

Membandingkan dengan Ringkasan 1.

Tampilan pembatasan

Tampilan Containment merupakan "tampilan menyeluruh" dari struktur objek aplikasi. Ini memungkinkan Anda mengintip ke dalam penutupan fungsi, mengamati objek internal VM yang bersama-sama membentuk objek JavaScript Anda, dan memahami berapa banyak memori yang digunakan aplikasi Anda pada tingkat yang sangat rendah.

Tampilan ini menyediakan beberapa titik masuk:

  • Objek DOMWindow. Objek global untuk kode JavaScript.
  • Root GC. Root GC yang digunakan oleh pembersih sampah memori 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 mesin virtual JavaScript untuk memungkinkan otomatisasi, misalnya, node DOM dan aturan CSS.

Tampilan Pembatasan.

Bagian Retainer

Bagian Retainer di bagian bawah panel Memory menampilkan objek yang mengarah ke objek yang dipilih dalam tampilan.

Bagian Retainer.

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

Menemukan objek tertentu

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

Beri nama fungsi untuk membedakan penutupan

Akan sangat membantu untuk menamai fungsi sehingga Anda dapat membedakan antaraclosure di 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;
}

Meskipun contoh ini melakukannya:

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.

Mengungkap kebocoran DOM

Profiler heap memiliki kemampuan untuk mencerminkan dependensi dua arah antara objek bawaan browser (node DOM dan aturan CSS) dan objek JavaScript. Cara ini membantu menemukan kebocoran tersembunyi yang terjadi karena sub-hierarki DOM terpisah yang terlupakan yang beterbangan.

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

  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 jika leafRef dibatalkan null, hierarki keseluruhan pada #tree merupakan kandidat untuk GC.

Subhierarki DOM