Saya akan mengimplementasikan kumpulan objek untuk sistem partikel saya di Jawa, kemudian saya menemukan ini di Wikipedia. Singkatnya, dikatakan bahwa kumpulan objek tidak layak digunakan dalam bahasa yang dikelola seperti Java dan C #, karena alokasi hanya membutuhkan puluhan operasi dibandingkan dengan ratusan dalam bahasa yang tidak dikelola seperti C ++.
Tapi seperti yang kita semua tahu, setiap instruksi dapat merusak kinerja game. Misalnya, kumpulan klien dalam MMO: klien tidak akan masuk dan keluar dari pool terlalu cepat. Tetapi partikel bisa diperbarui puluhan kali dalam sedetik.
Pertanyaannya adalah: apakah layak menggunakan kumpulan objek untuk partikel (khususnya, yang mati dan dibuat ulang dengan cepat) dalam bahasa yang dikelola?
sumber
Untuk Java tidak begitu membantu untuk menyatukan objek * karena siklus GC pertama untuk objek yang masih ada akan mengubah mereka dalam memori, memindahkannya keluar dari ruang "Eden" dan berpotensi kehilangan lokalitas spasial dalam proses tersebut.
Java menawarkan alokasi burst cepat menggunakan pengalokasi sekuensial ketika Anda dengan cepat mengalokasikan objek ke ruang Eden. Strategi alokasi sekuensial itu super cepat, lebih cepat daripada
malloc
di C karena hanya pooling memory yang sudah dialokasikan secara berurutan lurus, tetapi ia datang dengan sisi negatifnya bahwa Anda tidak dapat membebaskan potongan memori individual. Ini juga merupakan trik yang berguna dalam C jika Anda hanya ingin mengalokasikan hal-hal yang super cepat untuk, katakanlah, struktur data di mana Anda tidak perlu menghapus apa pun darinya, cukup tambahkan semuanya lalu gunakan dan buang semuanya nanti.Karena kelemahan ini karena tidak dapat membebaskan objek individual, Java GC, setelah siklus pertama, akan menyalin semua memori yang dialokasikan dari ruang Eden ke wilayah memori baru menggunakan pengalokasi memori yang lebih lambat dan lebih bertujuan umum yang memungkinkan memori untuk dibebaskan dalam potongan individu di utas yang berbeda. Kemudian ia dapat membuang memori yang dialokasikan di ruang Eden secara keseluruhan tanpa repot dengan objek individual yang sekarang telah disalin dan tinggal di tempat lain dalam memori. Setelah siklus GC pertama itu, objek Anda bisa menjadi terfragmentasi dalam memori.
Karena objek dapat berakhir terfragmentasi setelah siklus GC pertama, manfaat dari pengumpulan objek ketika itu terutama untuk meningkatkan pola akses memori (lokalitas referensi) dan mengurangi alokasi / deallokasi overhead sebagian besar hilang ... begitu banyak bahwa Anda akan mendapatkan referensi lokal yang lebih baik biasanya dengan hanya mengalokasikan partikel baru setiap saat dan menggunakannya saat mereka masih segar di ruang Eden dan sebelum mereka menjadi "tua" dan berpotensi tersebar di memori. Namun, apa yang bisa sangat membantu (seperti mendapatkan kinerja menyaingi C di Jawa) adalah untuk menghindari menggunakan objek untuk partikel Anda dan mengumpulkan data primitif lama polos. Sebagai contoh sederhana, alih-alih:
Lakukan sesuatu seperti:
Sekarang untuk menggunakan kembali memori untuk partikel yang ada, Anda dapat melakukan ini:
Sekarang ketika
nth
partikel mati, untuk memungkinkannya untuk digunakan kembali, dorong ke daftar gratis seperti:Saat menambahkan partikel baru, lihat apakah Anda dapat mengeluarkan indeks dari daftar gratis:
Ini bukan kode yang paling menyenangkan untuk dikerjakan, tetapi dengan ini Anda harus bisa mendapatkan beberapa simulasi partikel yang sangat cepat dengan pemrosesan partikel sekuensial yang selalu sangat ramah terhadap cache karena semua data partikel akan selalu disimpan secara bersebelahan. Jenis rep SoA ini juga mengurangi penggunaan memori karena kita tidak perlu khawatir tentang padding, metadata objek untuk refleksi / pengiriman dinamis, dan itu memecah bidang panas dari bidang dingin (misalnya, kita tidak perlu khawatir dengan data bidang seperti warna partikel selama lulus fisika sehingga akan sia-sia untuk memuatnya ke dalam garis cache hanya untuk tidak menggunakannya dan mengusirnya).
Untuk membuat kode lebih mudah untuk dikerjakan, mungkin ada baiknya menulis kontainer resizable dasar Anda sendiri yang menyimpan array float, array integer, dan array boolean. Sekali lagi Anda tidak dapat menggunakan obat generik dan di
ArrayList
sini (setidaknya sejak terakhir kali saya memeriksa) karena itu memerlukan objek yang dikelola GC, bukan data primitif yang berdekatan. Kami ingin menggunakan array yang berdekatanint
, misalnya, bukan array yang dikelola GCInteger
yang tidak harus berdekatan setelah meninggalkan ruang Eden.Dengan array tipe primitif, mereka selalu dijamin bersebelahan, sehingga Anda mendapatkan lokalitas referensi yang sangat diinginkan (untuk pemrosesan partikel berurutan itu membuat perbedaan dunia) dan semua manfaat yang ingin disediakan oleh kumpulan objek. Dengan berbagai objek, itu agak analog dengan array pointer yang mulai menunjuk ke objek dengan cara yang berdekatan dengan asumsi Anda mengalokasikan semuanya sekaligus ke ruang Eden, tetapi setelah siklus GC, dapat menunjuk seluruh tempatkan di memori.
sumber