Ini bisa mudah untuk game dengan cakupan yang ditentukan dengan baik, tetapi pertanyaannya adalah tentang game sandbox, di mana pemain diizinkan untuk membuat dan membangun apa pun .
Kemungkinan teknik:
- Gunakan kumpulan memori dengan batas atas.
- Hapus objek yang tidak lagi dibutuhkan secara berkala.
- Alokasikan jumlah memori tambahan di awal sehingga dapat dibebaskan nanti sebagai mekanisme pemulihan. Saya akan mengatakan sekitar 2-4 MB.
Ini lebih cenderung terjadi pada platform seluler / konsol di mana memori biasanya terbatas tidak seperti PC 16 GB Anda. Saya berasumsi Anda memiliki kontrol penuh atas alokasi / deallokasi memori dan tidak ada pengumpulan sampah yang terlibat. Itu sebabnya saya menandai ini sebagai C ++.
Harap dicatat bahwa saya tidak berbicara tentang C ++ Efektif Item 7 "Bersiaplah untuk kondisi kehabisan memori" , meskipun itu relevan, saya ingin melihat jawaban yang lebih terkait dengan pengembangan game, di mana Anda biasanya memiliki kontrol lebih besar atas apa kejadian.
Untuk meringkas pertanyaan, bagaimana Anda mempersiapkan kondisi kehabisan memori untuk game sandbox, ketika Anda menargetkan platform dengan konsol / ponsel memori terbatas?
sumber
Jawaban:
Secara umum, Anda tidak menangani kehabisan memori. Satu-satunya pilihan yang waras dalam perangkat lunak sebesar dan serumit gim adalah dengan hanya menabrak / menegaskan / mengakhiri pengalokasi memori Anda sesegera mungkin (terutama dalam pembuatan debug). Kondisi kehabisan memori diuji dan ditangani dalam beberapa perangkat lunak sistem inti atau perangkat lunak server dalam beberapa kasus tetapi tidak biasanya di tempat lain.
Ketika Anda memiliki kap memori atas, Anda hanya memastikan bahwa Anda tidak pernah membutuhkan lebih dari jumlah memori itu. Misalnya, Anda dapat menyimpan jumlah maksimum NPC yang diizinkan pada suatu waktu, dan cukup berhenti memunculkan NPC yang tidak penting baru begitu batasan itu dipukul. Untuk NPC esensial Anda dapat meminta mereka mengganti yang tidak penting atau memiliki kumpulan / batas terpisah untuk NPC esensial yang desainer Anda ketahui untuk mendesain (mis. Jika Anda hanya dapat memiliki 3 NPC esensial, desainer tidak akan menempatkan lebih dari 3 dalam area / chunk - alat yang baik akan membantu desainer melakukan ini dengan benar dan tentu saja pengujian sangat penting).
Sistem streaming yang sangat bagus juga penting terutama untuk gim sandbox. Anda tidak perlu menyimpan semua NPC dan item dalam memori. Saat Anda bergerak melalui potongan dunia, potongan baru akan mengalir dan potongan lama mengalir keluar. Ini umumnya akan mencakup NPC dan item serta medan. Desain dan batas teknis pada batas item harus ditetapkan dengan sistem ini dalam pikiran, mengetahui bahwa paling banyak potongan X lama akan disimpan dan potongan pro-aktif Y potongan baru akan dimuat, sehingga permainan perlu memiliki ruang untuk menyimpan semua data potongan X + Y + 1 dalam memori.
Beberapa gim berusaha menangani situasi kehabisan memori dengan pendekatan dua lintasan. Ingatlah bahwa sebagian besar gim memiliki banyak data yang secara teknis tidak perlu di-cache (katakanlah, potongan lama yang disebutkan di atas) dan alokasi memori mungkin melakukan sesuatu seperti:
Ini adalah langkah terakhir untuk menangani situasi tak terduga dalam rilis tetapi selama debugging dan pengujian Anda mungkin harus segera crash. Anda tidak ingin harus bergantung pada hal-hal semacam ini (terutama karena membuang cache mungkin memiliki beberapa konsekuensi kinerja yang serius).
Anda mungkin juga mempertimbangkan untuk membuang salinan beresolusi tinggi dari beberapa data, misalnya Anda mungkin membuang tingkat tekstur mipmap beresolusi tinggi jika Anda kehabisan memori GPU (atau memori apa pun dalam arsitektur memori bersama). Ini biasanya membutuhkan banyak pekerjaan arsitektur untuk membuatnya sepadan.
Perhatikan bahwa beberapa gim sandbox yang sangat tidak terbatas dapat dengan mudah hanya macet, bahkan pada PC (ingat bahwa aplikasi 32-bit yang umum memiliki batas ruang alamat 2-3GB bahkan jika Anda memiliki PC dengan 128GB RAM; 64- bit OS dan perangkat keras memungkinkan lebih banyak aplikasi 32-bit berjalan secara bersamaan tetapi tidak dapat melakukan apa pun untuk membuat biner 32-bit memiliki ruang alamat yang lebih besar). Pada akhirnya, Anda memiliki dunia gim yang sangat fleksibel yang membutuhkan ruang memori tanpa batas untuk dijalankan dalam setiap kasus atau Anda memiliki dunia yang sangat terbatas dan terkontrol yang selalu bekerja dengan sempurna dalam memori yang terbatas (atau sesuatu di suatu tempat di antaranya).
sumber
Aplikasi ini biasanya diuji pada platform yang ditargetkan dengan skenario kasus terburuk dan Anda akan selalu siap untuk platform yang Anda targetkan. Idealnya aplikasi tidak boleh macet, tetapi selain optimasi untuk perangkat tertentu, ada sedikit pilihan ketika Anda menghadapi peringatan kehabisan memori.
Praktik terbaik adalah memiliki kolam yang telah dialokasikan sebelumnya dan permainan menggunakan dari awal semua memori yang dibutuhkan. Jika gim Anda memiliki maksimal 100 unit daripada memiliki kelompok untuk 100 unit dan hanya itu. Jika 100 unit melebihi persyaratan mem untuk satu perangkat yang ditargetkan maka Anda dapat mengoptimalkan unit untuk menggunakan lebih sedikit memori atau mengubah desain ke maksimum 90 unit. Seharusnya tidak ada kasus di mana Anda dapat membangun hal-hal yang tidak terbatas, harus selalu ada batasnya. Akan sangat buruk untuk permainan kotak pasir untuk digunakan
new
untuk setiap contoh karena Anda tidak pernah dapat memprediksi penggunaan mem dan kerusakan jauh lebih buruk daripada batasan.Juga desain game harus selalu mengingat perangkat yang ditargetkan terendah karena jika Anda mendasarkan desain Anda dengan hal-hal "tidak terbatas" di dalamnya maka akan jauh lebih sulit untuk menyelesaikan masalah memori atau mengubah desain nanti.
sumber
Nah, Anda dapat mengalokasikan sekitar 16 MiB (hanya untuk menjadi 100% yakin) pada saat startup atau bahkan pada
.bss
saat kompilasi, dan menggunakan "pengalokasi aman", dengan tanda tangan sepertiinline __attribute__((force_inline)) void* alloc(size_t size)
(__attribute__((force_inline))
adalah GCC /mingw-w64
atribut yang memaksa inlining dari bagian kode kritis bahkan jika optimasi dinonaktifkan, meskipun itu harus diaktifkan untuk permainan) alih-alihmalloc
mencobavoid* result = malloc(size)
dan jika gagal, lepaskan cache, bebaskan memori cadangan (atau beri tahu kode lain untuk menggunakan.bss
benda itu tetapi itu di luar ruang untuk jawaban ini) dan flush data yang belum disimpan (simpan dunia ke disk, jika Anda menggunakan konsep potongan Minecraft, panggil sesuatu sepertisaveAllModifiedChunks()
). Kemudian, jikamalloc(16777216)
(mengalokasikan 16 MiB ini lagi) gagal (lagi, ganti dengan analog untuk.bss
), hentikan game dan tunjukkanMessageBox(NULL, "*game name* couldn't continue because of lack of free memory, but your world was safely saved. Try closing background applications and restarting the game", "*Game name*: out of memory", MB_ICONERROR)
atau alternatif spesifik platform. Menyatukan semuanya:Anda dapat menggunakan solusi yang sama dengan
std::set_new_handler(myHandler)
manamyHandler
yangvoid myHandler(void)
yang disebut ketikanew
gagal:sumber