Pengantar
Jadi, Anda mendapatkan email yang menyatakan bahwa game web / aplikasi web Anda berperforma buruk setelah jangka waktu tertentu, Anda memeriksa kode, tidak melihat apa pun yang menonjol, hingga Anda membuka alat performa memori Chrome, dan melihat ini:

Salah satu rekan kerja Anda tertawa, karena dia menyadari bahwa Anda mengalami masalah performa terkait memori.
Dalam tampilan grafik memori, pola gigi gergaji ini sangat menunjukkan potensi masalah performa yang kritis. Seiring penggunaan memori meningkat, Anda akan melihat area diagram juga meningkat dalam rekaman linimasa. Jika diagram tiba-tiba menurun, itu adalah instance saat Garbage Collector telah berjalan, dan membersihkan objek memori yang direferensikan.

Dalam grafik seperti ini, Anda dapat melihat bahwa ada banyak peristiwa Pembersihan Sampah Memori yang terjadi, yang dapat membahayakan performa aplikasi web Anda. Artikel ini akan membahas cara mengontrol penggunaan memori, sehingga mengurangi dampaknya terhadap performa Anda.
Pembersihan sampah memori dan biaya performa
Model memori JavaScript dibuat berdasarkan teknologi yang dikenal sebagai Pemroses Sampah. Dalam banyak bahasa, programmer bertanggung jawab secara langsung untuk mengalokasikan dan mengosongkan memori dari Memory Heap sistem. Namun, sistem Garbage Collector mengelola tugas ini atas nama programmer, yang berarti bahwa objek tidak langsung dibebaskan dari memori saat programmer mendereferensikannya, tetapi pada lain waktu saat heuristik GC memutuskan bahwa akan bermanfaat untuk melakukannya. Proses pengambilan keputusan ini mengharuskan GC menjalankan beberapa analisis statistik pada objek aktif dan tidak aktif, yang memerlukan waktu untuk dilakukan.
Pembersihan sampah sering kali digambarkan sebagai kebalikan dari pengelolaan memori manual, yang mengharuskan programmer menentukan objek mana yang akan dide-alokasikan dan dikembalikan ke sistem memori
Proses GC dalam mengambil kembali memori tidak gratis, biasanya proses ini mengurangi performa yang tersedia dengan mengambil blok waktu untuk melakukan tugasnya; selain itu, sistem itu sendiri yang membuat keputusan kapan harus dijalankan. Anda tidak memiliki kontrol atas tindakan ini, pulsa GC dapat terjadi kapan saja selama eksekusi kode, yang akan memblokir eksekusi kode hingga selesai. Durasi pulsa ini umumnya tidak diketahui oleh Anda; akan memerlukan waktu beberapa saat untuk dijalankan, bergantung pada cara program Anda menggunakan memori pada waktu tertentu.
Aplikasi berperforma tinggi mengandalkan batas performa yang konsisten untuk memastikan pengalaman yang lancar bagi pengguna. Sistem pembersihan sampah memori dapat mengganggu sasaran ini, karena dapat berjalan pada waktu acak untuk durasi acak, sehingga mengurangi waktu yang tersedia yang diperlukan aplikasi untuk memenuhi sasaran performanya.
Mengurangi Churn Memori, Mengurangi beban Pembersihan Sampah Memori
Seperti yang telah disebutkan, pulsa GC akan terjadi setelah serangkaian heuristik menentukan bahwa ada cukup objek tidak aktif sehingga pulsa akan bermanfaat. Dengan demikian, kunci untuk mengurangi jumlah waktu yang diperlukan Garbage Collector dari aplikasi Anda terletak pada pengurangan kasus pembuatan dan rilis objek yang berlebihan sebanyak mungkin. Proses pembuatan/pembebasan objek ini sering disebut “churn memori”. Jika Anda dapat mengurangi churn memori selama masa aktif aplikasi, Anda juga akan mengurangi jumlah waktu yang diperlukan GC dari eksekusi. Artinya, Anda perlu menghapus / mengurangi jumlah objek yang dibuat dan dihancurkan, sehingga Anda harus berhenti mengalokasikan memori.
Proses ini akan memindahkan grafik memori Anda dari :

menjadi ini:

Dalam model ini, Anda dapat melihat bahwa grafik tidak lagi memiliki pola seperti gergaji gergaji, tetapi tumbuh sangat besar di awal, lalu perlahan meningkat dari waktu ke waktu. Jika Anda mengalami masalah performa karena churn memori, inilah jenis grafik yang sebaiknya Anda buat.
Beralih ke JavaScript memori statis
JavaScript Memori Statis adalah teknik yang melibatkan pra-alokasi, di awal aplikasi Anda, semua memori yang akan diperlukan selama masa aktifnya, dan mengelola memori tersebut selama eksekusi karena objek tidak lagi diperlukan. Kita dapat mencapai sasaran ini dalam beberapa langkah sederhana:
- Buat instrumen aplikasi Anda untuk menentukan jumlah maksimum objek memori aktif yang diperlukan (per jenis) untuk berbagai skenario penggunaan
- Terapkan kembali kode Anda untuk mengalokasikan jumlah maksimum tersebut terlebih dahulu, lalu ambil/lepas secara manual, bukan ke memori utama.
Pada kenyataannya, untuk mencapai #1, kita harus melakukan sedikit #2, jadi mari kita mulai dari sana.
Kumpulan Objek
Secara sederhana, penggabungan objek adalah proses mempertahankan kumpulan objek yang tidak digunakan yang memiliki jenis yang sama. Saat Anda memerlukan objek baru untuk kode, Anda akan mendaur ulang salah satu objek yang tidak digunakan dari kumpulan, bukan mengalokasikan objek baru dari Memory Heap sistem. Setelah kode eksternal selesai dengan objek, kode tersebut akan dikembalikan ke kumpulan, bukan dirilis ke memori utama. Karena objek tidak pernah didereferensi (alias dihapus) dari kode, objek tidak akan di-garbage collection. Dengan menggunakan kumpulan objek, kontrol memori akan kembali ke tangan programmer, sehingga mengurangi pengaruh pembersih sampah memori terhadap performa.
Karena ada kumpulan jenis objek heterogen yang dikelola aplikasi, penggunaan kumpulan objek yang tepat mengharuskan Anda memiliki satu kumpulan per jenis yang mengalami churn tinggi selama runtime aplikasi.
var newEntity = gEntityObjectPool.allocate();
newEntity.pos = {x: 215, y: 88};
//..... do some stuff with the object that we need to do
gEntityObjectPool.free(newEntity); //free the object when we're done
newEntity = null; //free this object reference
Untuk sebagian besar aplikasi, Anda pada akhirnya akan mencapai beberapa level dalam hal kebutuhan untuk mengalokasikan objek baru. Selama beberapa kali menjalankan aplikasi, Anda akan dapat memahami batas atas ini dengan baik, dan dapat mengalokasikan jumlah objek tersebut di awal aplikasi.
Pra-alokasi objek
Menerapkan penggabungan objek ke dalam project akan memberi Anda maksimum teoretis untuk jumlah objek yang diperlukan selama runtime aplikasi. Setelah menjalankan situs melalui berbagai skenario pengujian, Anda dapat memahami dengan baik jenis persyaratan memori yang akan diperlukan, dan dapat membuat katalog data tersebut di suatu tempat, serta menganalisisnya untuk memahami batas atas persyaratan memori untuk aplikasi Anda.
Kemudian, dalam versi pengiriman aplikasi, Anda dapat menetapkan fase inisialisasi untuk mengisi otomatis semua kumpulan objek ke jumlah yang ditentukan. Tindakan ini akan mendorong semua inisialisasi objek ke bagian depan aplikasi Anda, dan mengurangi jumlah alokasi yang terjadi secara dinamis selama eksekusi.
function init() {
//preallocate all our pools.
//Note that we keep each pool homogeneous wrt object types
gEntityObjectPool.preAllocate(256);
gDomObjectPool.preAllocate(888);
}
Jumlah yang Anda pilih sangat berkaitan dengan perilaku aplikasi Anda; terkadang jumlah maksimum teoretis bukanlah opsi terbaik. Misalnya, memilih maksimum rata-rata dapat memberi Anda jejak memori yang lebih kecil untuk pengguna non-pengguna berat.
Jauh dari solusi ajaib
Ada banyak klasifikasi aplikasi yang pola pertumbuhan memori statisnya dapat menjadi keuntungan. Namun, seperti yang ditunjukkan oleh rekan DevRel Chrome Renato Mangini, ada beberapa kelemahan.
Kesimpulan
Salah satu alasan JavaScript ideal untuk web adalah karena JavaScript adalah bahasa yang cepat, menyenangkan, dan mudah digunakan. Hal ini terutama karena batasan rendahnya terhadap pembatasan sintaksis dan penanganan masalah memori untuk Anda. Anda dapat membuat kode dan membiarkannya menangani pekerjaan yang berat. Namun, untuk aplikasi web berperforma tinggi, seperti game HTML5, GC sering kali menghabiskan kecepatan frame yang sangat diperlukan, sehingga mengurangi pengalaman pengguna akhir. Dengan beberapa instrumentasi yang cermat dan penggunaan kumpulan objek, Anda dapat mengurangi beban ini pada kecepatan frame, dan memanfaatkan kembali waktu tersebut untuk hal-hal yang lebih keren.
Kode Sumber
Ada banyak implementasi kumpulan objek yang beredar di web, jadi saya tidak akan membuat Anda bosan dengan implementasi lainnya. Sebagai gantinya, saya akan mengarahkan Anda ke artikel ini, yang masing-masing memiliki nuansa penerapan tertentu; yang penting, mengingat setiap penggunaan aplikasi mungkin memiliki kebutuhan penerapan tertentu.
- Kumpulan objek Gamecore.js
- Beej's Object Pools
- Koleksi objek super sederhana dari Emehrkay
- Koleksi objek game yang berfokus pada game dari Steven Lambert
- Penyiapan objectPool RenderEngine