Untuk menjalankan JavaScript, browser memerlukan sedikit memori, tetapi di suatu tempat Anda perlu menyimpan objek, primitif, fungsi yang dibuat untuk semua tindakan pengguna. Oleh karena itu, browser pertama-tama mengalokasikan jumlah RAM yang diperlukan, dan ketika objek tidak digunakan, ia membersihkannya secara independen.
Secara teori, itu terdengar bagus. Dalam praktiknya, pengguna membuka 20 tab dari YouTube, jejaring sosial, membaca sesuatu, bekerja, peramban memakan memori, seperti Hummer H2 - bensin. Pengumpul sampah, seperti monster ini dengan kain pel, mengaliri seluruh memori dan menambahkan kebingungan, semuanya melambat dan jatuh.

Untuk mencegah situasi seperti itu terjadi dan kinerja situs dan aplikasi kami tidak menderita, pengembang front-end harus tahu bagaimana sampah memengaruhi aplikasi, bagaimana browser mengumpulkannya dan mengoptimalkan kerja dengan memori, dan bagaimana semuanya berbeda dari kenyataan pahit. Ini hanya laporan
Andrei Roenko ( flapenguin ) di
Frontend Conf 2018 .
Kami menggunakan pengumpul sampah (bukan di rumah - dalam pengembangan front-end) setiap hari, tetapi kami tidak benar-benar berpikir tentang apa itu sama sekali, berapa biayanya bagi kami dan peluang serta keterbatasan apa yang dimilikinya.
Jika pengumpulan sampah benar-benar berfungsi dalam JavaScript, sebagian besar modul npm akan langsung terhapus setelah instalasi.
Tetapi sementara ini tidak demikian, dan kita akan berbicara tentang apa - tentang mengumpulkan benda-benda yang tidak perlu.
Tentang pembicara :
Andrei Roenko telah mengembangkan
Yandex.Map API , telah berada di frontend selama enam tahun sekarang, dia suka membuat abstraksi tinggi sendiri dan turun dari orang lain ke tanah.
Mengapa Anda membutuhkan pengumpulan sampah?
Perhatikan contoh Yandex.Maps. Yandex.Maps adalah layanan besar dan kompleks yang menggunakan banyak JS dan hampir semua API browser yang ada, kecuali untuk yang multimedia, dan waktu sesi rata-rata adalah 5-10 menit. Kelimpahan JavaScript menciptakan banyak objek. Menyeret peta, menambahkan organisasi, hasil pencarian, dan banyak peristiwa lain yang terjadi setiap detik menciptakan longsoran objek. Tambahkan ke Bereaksi ini dan objek menjadi lebih.
Namun, objek JS hanya menempati 30-40 Mb di peta. Untuk sesi Yandex.Maps yang panjang dan alokasi objek baru yang konstan, ini tidak cukup.
Alasan volume kecil benda-benda adalah bahwa mereka berhasil dikumpulkan oleh pengumpul sampah dan memori digunakan kembali.
Hari ini kita akan berbicara tentang pengumpulan sampah dari empat sisi:
- Teori Mari kita mulai dengannya untuk berbicara dalam bahasa yang sama dan saling memahami.
- Realitas yang keras. Pada akhirnya, komputer mengeksekusi kode mesin yang tidak ada semua abstraksi yang kita kenal. Mari kita coba mencari tahu bagaimana pengumpulan sampah bekerja pada level rendah.
- Realita peramban. Mari kita lihat bagaimana pengumpulan sampah diimplementasikan di mesin dan browser modern, dan kesimpulan apa yang bisa kita tarik dari ini.
- Kehidupan sehari-hari - mari kita bicara tentang penerapan praktis dari pengetahuan yang diperoleh dalam kehidupan sehari-hari.
Kami mendukung semua pernyataan dengan contoh bagaimana Anda bisa dan bagaimana Anda tidak perlu melakukannya.
Kenapa tahu semua ini?
Pengumpulan sampah adalah hal yang tidak terlihat bagi kami, namun, mengetahui bagaimana mengaturnya Anda akan:
- Pikirkan alat yang Anda gunakan, yang berguna dalam pekerjaan Anda.
- Memahami di mana mengoptimalkan aplikasi yang sudah dirilis dan bagaimana merancang yang di masa depan sehingga mereka bekerja lebih baik dan lebih cepat
- Ketahui cara untuk tidak membuat kesalahan umum dan berhenti menghabiskan sumber daya untuk "optimisasi" yang tidak berguna dan berbahaya.
Teori
Joel Spolsky pernah berkata:
Semua abstraksi non-sepele bocor.
Pengumpul sampah adalah abstraksi non-sepele besar yang ditambal dari semua sisi. Untungnya, itu mengalir sangat jarang.
Mari kita mulai dengan sebuah teori, tetapi tanpa definisi yang membosankan. Mari kita menganalisis karya pengumpul menggunakan kode sederhana sebagai contoh:
window.Foo = class Foo { constructor() { this.x = { y: 'y' }; } work(name) { let z = 'z'; return function () { console.log(name, this.xy, z); this.x = null; }.bind(this); } };
- Ada kelas dalam kode.
- Kelas memiliki konstruktor .
- Metode kerja mengembalikan fungsi terkait.
- Di dalam fungsi, ini dan beberapa variabel dari penutupan digunakan.
Mari kita lihat bagaimana kode ini akan berperilaku jika kita menjalankannya seperti ini:
var foo = new Foo();
Mari kita menganalisis kode dan komponen-komponennya secara lebih rinci dan mulai dengan kelas.
Deklarasi kelas

Kita dapat mengasumsikan bahwa kelas dalam ECMAScript 2015 hanyalah gula sintaksis untuk fungsi. Semua fungsi memiliki:
- Fungsi. [[Prototipe]] adalah prototipe asli dari fungsi tersebut.
- Foo.prototype adalah prototipe untuk objek yang baru dibuat.
- Foo.prototype memiliki tautan kembali ke konstruktor melalui bidang konstruktor. Ini adalah objek, jadi ia mewarisi dari Object.prototype .
- Metode kerja adalah fungsi terpisah yang memiliki tautan, mirip dengan konstruktor, karena keduanya sama-sama fungsi. Dia juga dapat mengatur prototipe dan menyebutnya melalui yang baru, tetapi jarang ada yang menggunakan perilaku ini.
Prototipe membutuhkan banyak ruang di sirkuit, jadi mari kita ingat, tetapi akan menghapusnya untuk kesederhanaan.
Membuat Obyek Kelas

- Kami menempatkan kelas kami di jendela, karena kelas tidak sampai di sana secara default.
- Buat objek kelas.
- Membuat objek secara otomatis memperlihatkan prototipe objek kelas di Foo.prototype. Oleh karena itu, ketika Anda mencoba memanggil metode kerja pada objek, ia akan tahu jenis pekerjaan apa itu.
- Konstruktor kami membuat bidang x pada objek dari objek dengan string.
Inilah yang terjadi:

Metode mengembalikan fungsi terikat - ini adalah objek "ajaib" khusus di JS, yang terdiri dari terikat ini dan fungsi yang harus dipanggil. Fungsi terkait juga memiliki prototipe dan prototipe lain, tetapi kami tertarik pada penutupan. Berdasarkan spesifikasi, penutupan disimpan di Lingkungan. Kemungkinan besar Anda lebih akrab dengan kata Lingkup, tetapi
dalam spesifikasi bidang ini disebut Lingkungan .

Lingkungan menyimpan referensi ke LexicalEnvironment. Ini adalah objek yang kompleks, lebih rumit dari pada slide, ini menyimpan tautan ke segala sesuatu yang dapat diakses dari suatu fungsi. Misalnya, jendela, Foo, nama, dan z. Itu juga menyimpan tautan ke bahkan apa yang tidak Anda gunakan secara eksplisit. Misalnya, Anda dapat menggunakan eval dan secara tidak sengaja menggunakan objek yang tidak digunakan, tetapi JS tidak boleh rusak.
Jadi, kami membangun semua benda dan sekarang kami akan menghancurkan segalanya.
Hapus tautan ke objek
Mari kita mulai dengan menghapus tautan ke objek, tautan ini dalam diagram disorot dengan warna merah.

Kami menghapus dan tidak ada yang terjadi, karena dari
jendela ke objek ada jalan melalui
fungsi fungsi
terikat .

Ini mendorong kita ke kesalahan tipikal.
Kesalahan umum - langganan yang terlupakan
externalElement.addEventListener('click', () => { if (this.shouldDoSomethingOnClick) { this.doSomething(); } })
Terjadi ketika Anda berlangganan: menggunakan
ini, secara eksplisit melalui fungsi bind atau melalui panah; gunakan sesuatu di penutupan. Kemudian Anda lupa untuk berhenti berlangganan, dan masa hidup objek Anda atau apa yang ada di sirkuit menjadi sama dengan masa berlangganan. Misalnya, jika ini adalah elemen DOM yang tidak Anda sentuh, maka kemungkinan besar ini adalah waktu sampai akhir masa halaman.
Untuk mengatasi masalah ini:
- Berhenti berlangganan.
- Pikirkan selama masa berlangganan, dan siapa yang memilikinya.
- Jika karena alasan tertentu Anda tidak dapat berhenti berlangganan, maka batalkan tautannya (apa pun = nol), atau bersihkan semua bidang objek. Jika objek Anda bocor, itu akan kecil dan itu tidak sayang.
- Gunakan WeakMap, mungkin ini akan membantu dalam beberapa situasi.
Hapus referensi kelas
Teruskan dan coba hapus tautan merah yang disorot kelas.

Kami menghapus tautan dan tidak ada perubahan bagi kami. Alasannya adalah bahwa kelas dapat diakses melalui BoundThis, di mana ada tautan ke prototipe, dan di dalam prototipe ada tautan kembali ke konstruktor.
Kesalahan umum pekerjaan tidak berguna
Mengapa semua demonstrasi ini dibutuhkan? Karena ada sisi lain dari masalah ketika orang mengambil saran untuk membatalkan tautan terlalu harfiah dan membatalkan segala sesuatu secara umum.
destroy() { this._x = null; this._y = null;
Ini adalah pekerjaan yang sangat tidak berharga. Jika objek hanya terdiri dari referensi ke objek lain dan tidak ada sumber daya di sana, maka tidak perlu menghancurkan (). Cukup kehilangan referensi ke objek, dan dia akan mati sendiri.
Tidak ada saran universal. Bila perlu, batalkan, dan jika tidak, jangan batalkan. Memusatkan perhatian bukanlah kesalahan, tetapi hanya pekerjaan sia-sia.
Silakan. Panggil metode fungsi terikat dan itu akan menghapus tautan dari [objek Foo] ke [Obyek objek]. Ini akan mengarah pada fakta bahwa objek-objek yang terpisah dalam sebuah persegi panjang biru muncul dalam diagram.

Objek-objek ini adalah sampah JS. Dia baik-baik saja. Namun, ada sampah yang tidak bisa dikumpulkan.
Sampah yang tidak mau
Di banyak API peramban, Anda dapat membuat dan menghancurkan objek. Jika objek tidak dihancurkan, maka tidak ada kolektor yang dapat merakitnya.
Objek dengan membuat / menghapus fungsi pasangan:
- createObjectURL (), revokeObjectURL ();
- WebGL: membuat / menghapus Program / Shader / Buffer / Tekstur / dll;
- ImageBitmap.close ();
- indexDb.close ().
Misalnya, jika Anda lupa untuk menghapus ObjectURL dari video 200 MB, maka 200 MB ini akan tetap berada dalam memori sampai akhir masa halaman dan bahkan lebih lama, karena ada pertukaran data antara tab. Demikian pula di WebGL, indexDb, dan API browser lainnya dengan sumber daya yang serupa.
Untungnya, dalam contoh kita, persegi panjang biru hanya berisi objek JavaScript, jadi ini hanya sampah yang bisa dihapus.
Langkah selanjutnya adalah menghapus tautan terakhir dari kiri ke kanan. Ini adalah referensi ke metode yang kami terima, fungsi terkait.

Setelah dihapus, kita tidak akan memiliki tautan ke kiri dan kanan? Bahkan, masih ada tautan dari penutupan.

Penting bahwa tidak ada tautan dari kiri ke kanan, karena itu semua kecuali jendela adalah sampah dan akan mati.
Catatan penting : ada referensi melingkar di sampah, yaitu objek yang saling merujuk. Kehadiran tautan semacam itu tidak mempengaruhi apa-apa, karena pengumpul sampah tidak mengumpulkan benda-benda individual, tetapi seluruh sampah.

Kami melihat contoh-contohnya dan sekarang pada level intuitif kami memahami apa itu sampah, tetapi mari kita berikan definisi yang lengkap tentang konsep tersebut.
Sampah adalah segala sesuatu yang bukan benda hidup.
Segalanya menjadi sangat jelas. Tapi apa benda hidup itu?
Objek hidup adalah objek yang dapat dijangkau oleh tautan dari objek root.Dua konsep baru muncul: "ikuti tautan" dan "objek root". Salah satu objek root yang sudah kita ketahui adalah window, jadi mari kita mulai dengan tautannya.
Apa artinya mengikuti tautan?
Ada banyak objek yang saling terkait dan merujuk satu sama lain. Kami akan melambai di sepanjang mereka, mulai dengan objek root.
Kami menginisialisasi langkah pertama, dan kemudian melanjutkan sesuai dengan algoritma berikut: katakanlah semua yang ada di puncak gelombang adalah benda hidup dan lihat apa yang mereka rujuk.

Kami menginisialisasi langkah pertama. Kemudian kita akan bertindak sesuai dengan algoritma berikut: katakanlah bahwa segala sesuatu yang kuning pada puncak gelombang adalah benda hidup dan mari kita lihat apa yang mereka rujuk.
Apa yang mereka rujuk, kami akan membuat lambang baru dari gelombang:

Selesai dan mulai lagi dari awal:
- Kami menghidupkan kembali.
- Kami melihat apa yang mereka rujuk.
- Buat lambang gelombang baru, benda bernyawa.
- Kami melihat apa yang mereka rujuk.

Memperhatikan bahwa satu panah menunjuk ke objek yang sudah hidup, kita tidak melakukan apa-apa. Lebih lanjut menurut algoritma, sampai objek untuk pergi kehabisan. Lalu kami mengatakan bahwa kami menemukan semua benda hidup, dan yang lainnya adalah sampah.

Proses ini disebut
penandaan .
Apa maksud objek root?
- Jendela
- Hampir semua API browser.
- Semua janji.
- Segala sesuatu yang dimasukkan ke dalam Microtask dan Macrotask.
- Pengamat mutasi, RAF, Idle-callbacks. Segala sesuatu yang dapat dicapai dari apa yang ada di RAF tidak dapat dihapus, karena jika Anda menghapus objek yang digunakan dalam RAF, maka sesuatu mungkin akan salah.
Perakitan dapat terjadi kapan saja. Setiap kali kawat gigi atau fungsi muncul, objek baru dibuat. Mungkin tidak ada cukup memori, dan kolektor akan mencari secara gratis:
function foo (a, b, c) { function bar (x, y, z) { const x = {};
Dalam hal ini, objek root akan menjadi segalanya di tumpukan panggilan. Jika Anda, misalnya, berhenti di baris dengan X dan menghapus apa yang dirujuk Y, maka aplikasi Anda akan macet. JS tidak mengizinkan kami melakukan kesembronoan seperti itu, jadi Anda tidak dapat menghapus objek dari Y.
Jika bagian sebelumnya tampak rumit, maka itu akan menjadi lebih sulit.
Realitas yang keras
Mari kita bicara tentang dunia mesin di mana kita berurusan dengan besi, dengan media fisik.
Memori adalah satu array besar di mana angka-angka terletak, misalnya: Uint32Array baru (16 * 2 ** 30).
Mari kita membuat objek dalam memori dan menambahkannya dari kiri ke kanan. Kami membuat satu, kedua, ketiga - semuanya berukuran berbeda. Kami menempatkan tautan di sepanjang jalan.

Pada objek ketujuh, tempat itu telah berakhir, karena kita memiliki 2 kotak gratis, tetapi kita membutuhkan 5.
Apa yang bisa dilakukan di sini? Opsi pertama adalah crash. Di halaman pada tahun 2018, setiap orang memiliki MacBook terbaru dan 16 GB RAM. Tidak ada situasi ketika tidak ada memori!
Namun, membiarkan segala sesuatunya berjalan dengan baik adalah ide yang buruk, karena di web ini mengarah ke layar yang sama:

Ini bukan perilaku yang kita inginkan dari program, tetapi secara umum itu valid. Ada kategori kolektor yang disebut
No-op .
Kolektor tanpa op
Pro:
- Kolektornya sangat sederhana.
- Hanya tidak ada pengumpulan sampah.
- Tidak perlu menulis atau memikirkan memori.
Cons:
- Semuanya jatuh sehingga tidak pernah naik lagi.
Untuk frontend, no-op collector tidak relevan, tetapi digunakan di backend. Misalnya, memiliki beberapa server di belakang penyeimbang, aplikasi diberikan 32 GB RAM dan kemudian dimatikan seluruhnya. Lebih sederhana dan kinerjanya hanya ditingkatkan dengan hanya me-restart ketika memori menjadi rendah.
Di web itu tidak mungkin dan Anda harus membersihkannya.
Cari dan hapus sampah
Kami mulai membersihkan dengan sampah. Kami sudah tahu bagaimana melakukannya. Sampah - objek C dan F dalam skema sebelumnya, karena Anda tidak dapat menjangkau mereka di sepanjang panah dari objek root.
Kami mengambil sampah ini, memberi makan kepada pencinta sampah dan Anda selesai.

Setelah dibersihkan, masalahnya tidak terpecahkan, karena lubang tetap ada dalam memori. Harap dicatat bahwa ada 7 kotak gratis, tetapi 5 di antaranya masih belum dapat kami alokasikan. Terjadi fragmentasi dan perakitan selesai. Algoritma dengan lubang seperti itu disebut
Mark and Sweep .
Tandai dan sapu
Pro:
- Algoritma yang sangat sederhana. Salah satu yang pertama yang akan Anda pelajari jika Anda mulai belajar tentang pengumpul sampah.
- Ini bekerja secara proporsional dengan jumlah sampah, tetapi hanya mengatasi ketika ada sedikit sampah.
- Jika Anda hanya memiliki benda hidup, maka dia tidak membuang waktu dan tidak melakukan apa-apa.
Cons:
- Dibutuhkan logika yang kompleks untuk mencari ruang kosong, karena ketika ada banyak lubang di memori, Anda harus mencoba objek di masing-masing untuk memahami apakah cocok atau tidak.
- Memori fragmen. Suatu situasi dapat terjadi bahwa dengan gratis 200 MB memori dibagi menjadi potongan-potongan kecil dan, seperti pada contoh di atas, tidak ada bagian memori yang solid untuk objek.
Kami mencari ide lain. Jika Anda melihat gambar dan berpikir, pikiran pertama adalah menggeser semuanya ke kiri. Kemudian di sebelah kanan akan ada satu potongan besar dan bebas, di mana objek kita akan dengan tenang pas.
Ada algoritma seperti itu dan disebut
Mark and Compact .
Tandai dan ringkas
Pro:
- Memori defragment.
- Ini bekerja secara proporsional dengan jumlah benda hidup, yang berarti dapat digunakan ketika praktis tidak ada puing.
Cons:
- Sulit dalam pekerjaan dan implementasi.
- Memindahkan benda. Kami memindahkan objek, menyalinnya, sekarang berada di tempat yang berbeda dan seluruh operasi cukup mahal.
- Ini membutuhkan 2-3 lintasan di seluruh memori, tergantung pada implementasinya - algoritme lambat.
Di sini kita sampai pada ide lain.
Pengumpulan sampah tidak gratis
Dalam API berkinerja tinggi seperti WebGL, WebAudio, dan WebGPU, yang masih dalam pengembangan, objek dibuat dan dihapus dalam fase terpisah. Spesifikasi ini ditulis sehingga pengumpulan sampah tidak dalam proses. Selain itu, bahkan tidak ada Janji di sana, tetapi tarik () - Anda hanya bertanya setiap frame: "Apakah ada sesuatu yang terjadi atau tidak?".
Semispace alias Lisp 2
Ada seorang kolektor lain yang ingin saya bicarakan. Bagaimana jika Anda tidak membebaskan memori, tetapi menyalin semua benda hidup di suatu tempat ke tempat lain.
Mari kita coba salin objek root "apa adanya", yang merujuk ke suatu tempat.

Dan kemudian semua orang.

Tidak ada puing atau lubang di memori di atas. Segalanya tampak baik-baik saja, tetapi muncul dua masalah:
- Objek duplikat - kami memiliki dua objek hijau dan dua yang biru. Yang mana yang akan digunakan?
- Tautan dari objek baru mengarah ke objek lama, dan bukan ke satu sama lain.
Dengan tautan, semuanya diselesaikan dengan bantuan "keajaiban" algoritmik khusus, dan kita dapat mengatasi duplikasi objek dengan menghapus semuanya di bawah ini.

Akibatnya, kami memiliki ruang kosong, dan hanya benda hidup dalam urutan normal di atas. Algoritma ini disebut
Semispace ,
Lisp 2, atau hanya "copy collector".
Pro:
- Memori defragment.
- Sederhana
- Dapat dikombinasikan dengan fase memotong.
- Ia bekerja secara proporsional dengan jumlah benda hidup dari waktu ke waktu.
- Bekerja dengan baik ketika ada banyak sampah. Jika Anda memiliki 2 GB memori dan 3 objek di dalamnya, maka Anda hanya akan mem-bypass 3 objek, dan sisa 2 GB tampaknya hilang.
Cons:
- Konsumsi memori ganda. Anda menggunakan memori 2 kali lebih banyak dari yang diperlukan.
- Memindahkan benda juga bukan operasi yang sangat murah.
Catatan: pengumpul sampah dapat memindahkan benda.
Di web, ini tidak relevan, tetapi pada Node.js bahkan sangat banyak. Jika Anda menulis ekstensi dalam C ++, maka bahasanya tidak tahu tentang semua ini, jadi ada tautan ganda yang disebut pegangan dan terlihat seperti ini: v8 :: Local <v8 :: String>.
Oleh karena itu, jika Anda akan menulis plugin untuk Node.js maka informasinya akan berguna.
Kami meringkas berbagai algoritma dengan kelebihan dan kekurangannya dalam tabel. Ini juga memiliki algoritma Eden, tetapi tentangnya nanti.

Saya benar-benar menginginkan algoritma tanpa kontra, tetapi ini bukan. Karena itu, kami mengambil yang terbaik dari semua dunia: kami menggunakan beberapa algoritma pada saat yang bersamaan. Dalam satu bagian memori, kami mengumpulkan sampah dengan satu algoritma, dan yang lain dengan algoritma lain.
Bagaimana cara memahami efektivitas algoritma dalam situasi seperti itu?
Kita dapat menggunakan pengetahuan tentang suami yang cerdas dari tahun 60an yang melihat semua program dan menyadari:
Hipotesis generasi yang lemah: sebagian besar benda mati muda.
Mereka ingin mengatakan bahwa semua program hanya menghasilkan sampah. Dalam upaya untuk menggunakan pengetahuan, kita akan sampai pada apa yang disebut "perakitan oleh generasi".
Perakitan generasi
Kami membuat dua keping memori yang tidak terhubung dengan cara apa pun: di sebelah kiri adalah Eden, dan di sebelah kanan adalah Mark dan Sweep yang lambat. Di Eden kita membuat objek. Banyak objek.

Ketika Eden mengatakan sudah penuh, kami mulai mengumpulkan sampah di dalamnya. Kami menemukan benda hidup dan menyalinnya ke kolektor lain.

Eden sendiri sudah sepenuhnya dibersihkan, dan kita bisa menambahkan objek lebih jauh lagi.

Mengandalkan hipotesis generasi, kami memutuskan bahwa objek c, g, saya kemungkinan besar akan hidup untuk waktu yang lama, dan kami dapat memeriksa mereka lebih jarang. Mengetahui hipotesis ini, Anda dapat menulis program yang menipu kolektor. Ini bisa dilakukan, tetapi saya tidak menyarankan Anda, karena hampir selalu akan menyebabkan efek yang tidak diinginkan. Jika Anda membuat sampah berumur panjang, pengumpul akan mulai percaya bahwa itu tidak perlu dikumpulkan.
Contoh klasik kecurangan adalah LRU-cache. Suatu objek terletak pada cache untuk waktu yang lama, kolektor melihatnya dan percaya bahwa ia belum akan mengoleksinya, karena objek tersebut akan hidup untuk waktu yang sangat lama. Kemudian objek baru masuk ke cache, dan yang lama didorong keluar dan tidak mungkin lagi untuk segera merakit objek besar ini.
Cara mengumpulkan sekarang kita tahu. Bicara tentang kapan mengumpulkan.
Kapan harus mengumpulkan?
Opsi termudah adalah ketika kita
hanya menghentikan semuanya , mulai build, dan kemudian mulai kerja JS lagi.

Di komputer modern, lebih dari satu utas eksekusi. Di web, ini familiar dari Pekerja Web. Mengapa tidak mengambil dan
memparalelkan proses perakitan . Melakukan beberapa operasi kecil pada saat yang sama akan lebih cepat daripada yang besar.

Gagasan lain adalah dengan hati-hati membuat snapshot dari keadaan saat ini, dan
membangun secara paralel dengan JS .

Jika ini menarik minat Anda, maka saya sarankan Anda untuk membaca:
- Satu-satunya dan buku rakitan utama, Buku Pegangan Koleksi Sampah.
- Wikipedia sebagai sumber universal.
- Situs web memorymanagement.org.
- Laporan dan artikel oleh Alexander Shepelev . Dia berbicara tentang Java, tetapi dalam hal sampah, Java dan V8 bekerja kurang lebih sama.
Realita peramban
Mari kita beralih ke bagaimana browser menggunakan semua yang kita bicarakan.
Mesin IOT
Mari kita mulai bukan dengan browser, tetapi dengan mesin Internet of Things: JerryScript dan Duktape. Mereka menggunakan Mark'n'sweep dan Stop the world algorithm.
Mesin IoT bekerja pada mikrokontroler, yang berarti: bahasanya lambat; hang kedua; fragmentasi dan semua ini untuk teko dengan pencahayaan :)
Jika Anda menulis Internet of Things dalam JavaScript, maka beri tahu kami di komentar? apakah ada gunanya?
Kami akan meninggalkan mesin IoT sendirian, kami tertarik pada:
- V8.
- SpiderMonkey Padahal, dia tidak punya logo. Logo buatan sendiri :)
- JavaScriptCore digunakan oleh WebKit.
- ChakraCore yang digunakan di Edge.

Semua mesin kira-kira sama, jadi kita akan berbicara tentang V8, sebagai yang paling terkenal.
V8
- Hampir semua JavaScript sisi server, karena itu Node.js.
- Hampir 80% dari JavaScript sisi klien.
- Pengembang yang paling mudah bergaul, ada banyak informasi dan kode sumber yang baik yang paling mudah dibaca.
V8 menggunakan perakitan generasi.

Satu-satunya perbedaan adalah bahwa kami dulu memiliki dua kolektor, dan sekarang tiga:
- Sebuah objek dibuat di Eden.
- Di beberapa titik di Eden, ada terlalu banyak sampah dan objek dipindahkan ke Semispace.
- Objeknya masih muda dan ketika kolektor menyadari bahwa benda itu terlalu tua dan membosankan, benda itu melemparkannya ke Mark dan Sweep, tempat pengumpulan sampah sangat jarang.
Anda dapat dengan jelas melihat tampilannya pada
jejak memori .

Beberapa gelombang besar dengan gelombang kecil terlihat. Yang kecil adalah majelis kecil, dan yang besar adalah yang utama.
Arti dari keberadaan kita, menurut hipotesis generasi, adalah menghasilkan sampah, jadi kesalahan selanjutnya adalah takut menciptakan sampah.
Sampah dapat dibuat ketika benar-benar sampah. , , , .
mark
V8 .

Stop the world, , JS, .
?
1 3%, .
3% = 1/33 GameDev. GameDev 3% 1 , . GameDev .
const pool = [new Bullet(), new Bullet(), ]; function getFromPool() { const bullet = pool.find(x => !x.inUse); bullet.isUse = true; return bullet; } function returnToPool(bullet) { bullet.inUse = false; }
, , 10 000 .
β . , . , .
: Chromium
, , , Chromium.
> performance.memory MemoryInfo { totalJSHeapSize: 10000000, usedJSHeapSize: 10000000, jsHeapSizeLimit: 2330000000 }
Chromium
performance.memory , , Chromium .
: Chromium 2 JavaScript.
, .
: Node
Node.js
process.memoryUsage , .
> process.memoryUsage() { rss: 22839296, heapTotal: 10207232, heapUsed: 5967968, external: 12829 }
, - , . . .
β , .
proposal , .
Node.js, c
node-weak , , .
let cached = new WeakRef(myJson);
, , - JS. , , , .
WebAssembly , . , , , .
: v8.dev JS.
?
DevTools :
Performance Memory . Chromium, , Firefox Safari .
Performance
Trace, Β«MemoryΒ» Performance, JS .

JS V8 , . . , GC 30 1200 JS, 1/40.
Memory
.

.

, . , , , V8 , . , .
, , Q ( compiled code) β React . , ?
, , , .
, .

, , , . , β 4 . , .

React, - : . , JSX.
Performance Memory , :
- Chromium: about:tracing.
- Firefox: about:memory about:performance, .
- Node β trace-gc, βexpose-gc, require('trace_events'). trace_events .
Ringkasan
- , , , .
- .
- . , ?
- , - .
- SPA, , 1 , .
- , - .
:
flapenguin.me ,
Twitter ,
GitHub .
- ++ . YouTube-
.
, 2018 , . Frontend Conf 2018.
, :)