Saya mengetahui beberapa game yang ditulis dalam C ++ tetapi tidak menggunakan pengecualian. Karena penanganan kegagalan alokasi memori di C ++ umumnya dibangun di sekitar std::bad_alloc
pengecualian, bagaimana game-game ini menangani kegagalan seperti itu?
Apakah mereka hanya crash, atau ada cara lain untuk menangani dan pulih dari kesalahan kehabisan memori?
c++
resource-management
memory
pengguna200783
sumber
sumber
std::terminate
, dan hanya itu. Tetapi kemudian di bawah batasan yang sama, alokasi dapat mengembalikan pointer nol alih-alih melemparkan pengecualian, dan hasilnya dapat diperiksa dan ditangani secara terpisah.ClassName variableName = new(nothrow) ClassName();
( jelas mengganti nama kelas, nama variabel, dll. ) Kemudian, jika alokasi gagal, Anda bisa mendeteksinya dengan mengatakanif(!variableName)
membiarkan kesalahan ditangani tanpa blok pengecualian coba-tangkap. Demikian juga, jika memori dialokasikan menggunakan fungsi sepertimalloc()
,,calloc()
dll., Maka kegagalan untuk mengalokasikan dapat dideteksi menggunakanif(!variableName)
metode yang sama tanpa perlu try-catch. Adapun cara permainan menangani kesalahan ini, baik, pada saat itu, tergantung pada pengembang game untuk memutuskan apakah itu crash atau tidak.Jawaban:
Sama seperti semua program rata-rata: Mereka tidak. *
Untuk sebagian besar aplikasi, tidak ada harapan pelanggan bahwa mereka terus bekerja setelah kehabisan memori. Semua game termasuk dalam "sebagian besar aplikasi" ini. Menghabiskan waktu dan uang untuk mengerjakan kasing tepi yang tidak diharapkan pelanggan untuk bekerja tidak masuk akal.
Pertanyaannya mirip dengan yang berikut:
Jawabannya sama: Ini adalah masalah pengguna. Game tidak peduli.
* Sebenarnya, mereka biasanya melakukan tangkapan tingkat tinggi dari perkecualian, dan menggunakan memori yang telah dialokasikan sebelumnya pada permulaan permainan untuk mencoba mencatat peristiwa tersebut sebelum crash / terminating. Log kemudian memungkinkan dukungan pelanggan untuk mengurangi waktu dalam masalah ini.
sumber
Biasanya skenario semacam ini tidak pernah terjadi.
Pertama, memori virtual pada sistem operasi modern berarti bahwa sangat tidak mungkin terjadi dalam operasi normal; kecuali jika Anda memiliki bug alokasi pelarian, game akan mengalokasikan memori dari ruang alamat virtual OS dan OS akan mencari setelah paging masuk dan keluar.
Itu semua baik dan bagus, tetapi itu tidak benar-benar berlaku untuk konsol atau OS yang lebih tua, jadi kedua, game bahkan tidak melakukan banyak alokasi dinamis kecil menggunakan pengalokasi perpustakaan standar pula. Alih-alih apa yang akan mereka lakukan adalah mengalokasikan kumpulan memori besar satu kali saja pada saat startup, dan menarik dari kumpulan itu untuk setiap alokasi runtime yang diperlukan (misalnya dengan menggunakan penempatan C ++ baru atau dengan menulis sistem manajemen memori mereka sendiri pada atas itu).
Itu juga melindungi terhadap kebocoran memori karena daripada harus melacak dan memperhitungkan setiap alokasi individu kecil, permainan bisa membuang seluruh kumpulan untuk mendapatkan kembali memori.
Dan ketiga, game akan selalu menetapkan spesifikasi minimum dan menganggarkan penggunaan memori mereka di dalamnya. Jadi, jika sebuah game ditentukan untuk membutuhkan 1gb RAM, itu berarti selama penggunaan memorinya tidak pernah melebihi 1gb, itu tidak perlu khawatir kehabisan RAM.
sumber
Yah, terutama, cara yang sama kita lakukan sebelum pengecualian ada - yang lama "periksa pendekatan nilai pengembalian". Jika pengalokasi tidak menggunakan pengecualian, biasanya akan kembali
null
ketika alokasi gagal. Gim yang ditulis dengan baik akan memeriksa itu dan menangani situasi dengan cara apa pun yang aman. Kadang-kadang, ini berarti menghentikan permainan (mis.std::terminate
) Atau setidaknya kembali ke kondisi aman yang diketahui terakhir (misalnya ketika Anda mengalokasikan dari kumpulan, Anda dapat membuang seluruh kumpulan dengan aman bahkan saat itu dalam kondisi yang tidak aman).Banyak game yang menggunakan pengecualian untuk kasus seperti ini bahkan saat itu. Ketika seseorang mengatakan "hindari menggunakan pengecualian dalam kode game", yang biasanya mereka maksudkan adalah "hanya menggunakan pengecualian untuk kasus yang benar-benar luar biasa, bukan untuk kontrol aliran biasa". Pengaturan untuk menangkap pengecualian memori murah - biaya sebagian besar dalam lemparan, dan komplikasi yang Anda dapatkan dengan menangani pengecualian. Tak satu pun dari mereka yang sangat penting dalam kasus kehabisan memori khas - Anda hampir selalu ingin mengakhiri.
Pikiran Anda, sebagian besar game hanya akan crash. Ini tidak gila seperti kedengarannya - Anda biasanya memiliki beberapa penggunaan memori sebagai target, dan pastikan gim Anda tidak mencapai batas itu (misalnya, dengan menggunakan batas jumlah unit dalam gim RTS, atau dengan membatasi jumlah musuh di bagian FPS). Bahkan jika Anda tidak, Anda biasanya tidak kehabisan memori pada sistem modern yang cukup - Anda kehabisan ruang alamat virtual (dalam aplikasi 32-bit) atau tumpukan, misalnya. OS sudah berpura-pura bahwa Anda memiliki memori sebanyak yang Anda minta - itulah salah satu abstraksi yang disediakan oleh memori virtual. Intinya, hanya karena Anda memiliki 256 MB RAM fisik tidak berarti bahwa aplikasi Anda tidak dapat menggunakan memori 4 GiB. Beberapa game bahkan mungkin tidak terlalu keberatan sehingga semua datanya tidak
sumber
Menangkap pengecualian dan Memutuskan untuk melakukan apa saat dan pengecualian dimunculkan adalah dua hal yang berbeda.
Anda harus memiliki logika yang kompleks untuk membebaskan memori yang tidak diperlukan oleh program Anda. Lebih buruk lagi, jika ada program atau pustaka lain yang sedang berjalan membocorkan memori maka Anda tidak dapat mengendalikannya
Hanya hal baik yang dapat Anda lakukan untuk mematikan dengan anggun dan itulah yang sebagian besar program akan lakukan. Anda bahkan tidak dapat memutuskan untuk menunggu hingga memori tersedia karena itu akan membuat program Anda tidak responsif.
sumber
std::terminate
, dan hanya itu. Tetapi dalam kondisi seperti itu, alokasi dapat mengembalikan pointer nol alih-alih melemparkan pengecualian, dan itu dapat ditangani secara terpisah.