Bagaimana game C ++ menangani kegagalan alokasi memori?


23

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_allocpengecualian, bagaimana game-game ini menangani kegagalan seperti itu?

Apakah mereka hanya crash, atau ada cara lain untuk menangani dan pulih dari kesalahan kehabisan memori?


1
Perhatikan bahwa ada lingkungan / OS tertentu di mana alokasi mengklaim berhasil, tetapi mencoba menggunakan memori crash program Anda (atau lainnya)
PlasmaHH

6
Jika alokasi gagal selama permainan, Gempa 3 akan menjatuhkan Anda kembali ke menu dengan pesan kesalahan. Saya percaya ini dimungkinkan oleh pengalokasi kolam Quake 3, yang bisa saja menjatuhkan seluruh kolam dan kembali ke menu dengan aman jika kolam habis.
Dietrich Epp

16
Biasanya, dengan menabrak.
user253751

1
Jika pengecualian benar-benar dinonaktifkan, program harus memanggil 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.
underscore_d

2
Di C ++, Anda bisa mengatakan ClassName variableName = new(nothrow) ClassName();( jelas mengganti nama kelas, nama variabel, dll. ) Kemudian, jika alokasi gagal, Anda bisa mendeteksinya dengan mengatakan if(!variableName)membiarkan kesalahan ditangani tanpa blok pengecualian coba-tangkap. Demikian juga, jika memori dialokasikan menggunakan fungsi seperti malloc(),, calloc()dll., Maka kegagalan untuk mengalokasikan dapat dideteksi menggunakan if(!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.
Spencer D

Jawaban:


63

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:

  • Bagaimana Anda menginstal game jika harddisk penuh?
  • Bagaimana Anda masih menjalankan game dengan fps tinggi pada PC di bawah spesifikasi minimum?

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.


2
Pada preallocating memori untuk logging, dll. Dalam hal terjadi kegagalan alokasi memori: stackoverflow.com/questions/7749066/…
bwDraco

23

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.


3
"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" - dan apa yang menurut Anda terjadi jika pool penuh?
user253751

@immibis - tolong lihat poin ketiga saya.
Maximus Minimus

2
@immibis Maksud Anda ... apa yang mereka lakukan jika kolam kosong? Tidak seperti memori sistem, ukuran dan penggunaan kumpulan sepenuhnya di bawah kendali aplikasi. Jadi kolam tidak dapat menjadi kosong kecuali aplikasi memiliki bug.
David Schwartz

@ Davidvidchchartz Atau kecuali jika kernel menggunakan memory overcommit. Linux melakukan ini. Bahkan mem-zero-out pool Anda tidak membantu jika kompresi pagefile diaktifkan melalui zswap atau zram.
Damian Yerrick

1
Ini sepertinya tidak menjawab pertanyaan yang sebenarnya tetapi sebaliknya menyatakan sesuatu yang mirip dengan "Kapal ini tidak dapat tenggelam sehingga untuk apa kita memerlukan prosedur darurat?"
Lilienthal

2

Yah, terutama, cara yang sama kita lakukan sebelum pengecualian ada - yang lama "periksa pendekatan nilai pengembalian". Jika pengalokasi tidak menggunakan pengecualian, biasanya akan kembali nullketika 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


1

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.


Jika game yang dimaksud secara harfiah "tidak menggunakan pengecualian" seperti kata OP, maka mereka tidak dapat menangkap, membesarkan, atau memprosesnya. Jika pengecualian dinonaktifkan dan seseorang melemparkannya, program harus memanggil 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.
underscore_d
Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.