C ++ oyunları bellek ayırma hatasını nasıl işler?


23

C ++ ile yazılmış birkaç istisna dışında olduğumu biliyorum ama istisnalar kullanmıyorum. C ++ 'da bellek ayırma arızasının ele alınması genellikle std::bad_allocistisna etrafında inşa edildiğinden , bu oyunlar böyle bir hatayı nasıl ele alır?

Basitçe çöküyorlar mı yoksa bellek yetersiz bir hatayı işlemek ve kurtarmanın başka bir yolu var mı?


1
Tahsisin başarılı olduğunu iddia ettiği, ancak belleği kullanmaya çalıştığınız programın (veya diğer) programınızı
çökertdiği

6
Oyun sırasında tahsis başarısız olursa Quake 3 sizi bir hata mesajı ile menüye geri bırakacaktır. Bunun, tüm havuzu bırakıp havuz bittiğinde menüye güvenle geri dönebilecek olan Quake 3'ün havuz ayırıcısı tarafından yapıldığına inanıyorum.
Dietrich Epp

16
Genellikle, çarparak.
kullanıcı253751,

1
İstisnalar gerçekten devre dışı bırakılmışsa, programın yerine çağırması gerekir std::terminate, hepsi bu. Ancak aynı kısıtlama altında tahsisat, bir istisna atmak yerine boş bir gösterici döndürebilir ve bu sonuç ayrı ayrı kontrol edilebilir ve kullanılabilir.
underscore_d

2
C ++ 'ta söyleyebilirsiniz ClassName variableName = new(nothrow) ClassName();( açıkça sınıf ismini, değişken ismini, vb. Değiştirmek ). Sonra, tahsis başarısız olursa, if(!variableName)hatanın bir try-catch istisna bloğu olmadan ele alınmasına izin verdiğini söyleyerek tespit edebilirsiniz . Bellek gibi bir fonksiyonunu kullanarak tahsis edilir Benzer şekilde, malloc(), calloc()ayırmaya, sonra vb arızaları aynı kullanılarak tespit edilebilir if(!variableName)bir deneyin-yakalamak gerek kalmadan bir yöntem. Oyunların bu hataları nasıl ele aldığına gelince, o noktada, çarpışıp çarpmamaya karar vermek oyunun geliştiricisine kalmış.
Spencer D

Yanıtlar:


63

Tüm ortalama programlarla aynı: Çalışmıyor. *

Çoğu uygulama için, bellek tükendiğinde müşterinin çalışmaya devam edeceği beklentisi yoktur. Tüm oyunlar bu "çoğu uygulama" nın altındadır. Müşterinin çalışmayı ummadığı bir durumda çalışmak için zaman ve para harcamak mantıklı gelmiyor.

Soru aşağıdakine benzer:

  • Sabit disk doluysa bir oyunu nasıl kurarsınız?
  • Oyunu, minimum özelliklerin altındaki bir PC'de hala yüksek fps hızında nasıl yürütüyorsunuz?

Cevap aynı: Bunlar kullanıcıların problemleri. Oyun umrunda değil.


* Aslında, genellikle istisnanın yüksek bir seviyesini yakalarlar ve oyunun başında çarpışma / sonlandırmadan önce günlüğe kaydetmeyi denemek için önceden ayrılmış bellek kullanırlar. Günlük, daha sonra müşteri desteğinin bu konuda daha az zaman kaybetmesine olanak sağlar.


2
Bellek ayırma arızası durumunda, günlüğe kaydetme vb. İçin önceden tahsis edilmiş bellek hakkında: stackoverflow.com/questions/7749066/…
bwDraco 23

23

Genelde bu tür bir senaryo asla gerçekleşmez.

Birincisi, modern işletim sistemlerinde sanal bellek, yine de normal işletimde gerçekleşmesi pek olası değildir; Kaçak bir tahsisat hatası yaşamadığınız sürece, oyun işletim sistemi sanal adres alanından bellek tahsis edecek ve işletim sistemi içeri ve dışarı sayfalamaya bakacak.

Hepsi iyi ve iyi, ancak konsollar veya eski işletim sistemleri için gerçekten geçerli değil, ikinci olarak, oyunlar yine de standart kütüphane tahsis ediciler kullanarak çok sayıda küçük dinamik tahsis bile yapmıyor. Bunun yerine, başlangıçta bir kereye mahsus olmak üzere büyük bir bellek havuzu ayırmak ve gerekli olan herhangi bir çalışma zamanı tahsisi için bu havuzdan aşağı çekmek (örneğin, C ++ yerleşimini yeni kullanarak veya kendi bellek yönetim sistemini yazarak) üstüne).

Bu aynı zamanda hafıza sızıntılarına karşı da korur çünkü her küçük bireysel tahsisatın izlenmesi ve hesaba katılması yerine, bir oyun hafızayı geri kazanmak için sadece tüm havuzu elden çıkarabilir.

Üçüncüsü, oyunlar her zaman minimum bir şartname koyacak ve hafıza kullanımlarını bunun içinde bütçeleyecek. Bir oyunun 1 gb RAM gerektirdiği belirtiliyorsa, bu, bellek kullanımı hiçbir zaman 1 gb'yi geçmediği sürece, RAM'in tükenmesi konusunda endişelenmesi gerekmediği anlamına gelir.


3
"Yapacakları şey yerine, başlangıçta yalnızca bir kez büyük bir bellek havuzu tahsis etmek ve gerekli olan çalışma zamanı tahsisleri için o havuzdan aşağı çekmek" - ve havuz doluysa ne olacağını düşünüyorsunuz?
kullanıcı253751, 3

@ immibis - lütfen üçüncü noktama bakın.
Maximus Minimus

2
@ immibis Yani ... havuz boşsa ne yaparlar? Sistem belleğinden farklı olarak, havuzun boyutu ve kullanımı tamamen uygulamanın kontrolü altındadır. Bu nedenle, uygulama bir hata olmadıkça havuz boş olamaz .
David Schwartz 9

@DavidSchwartz Veya çekirdek bellek overcommit kullanmıyorsa. Linux bunu yapar. Havuzunuzu sıfırlamak bile, sayfa dosyası sıkıştırma işlevinin zswap veya zram aracılığıyla etkinleştirilip etkinleştirilmemesi konusunda yardımcı olmaz.
Damian Yerrick

1
Bu, asıl soruya cevap vermiyor gibi görünüyor ama bunun yerine "Bu gemi batmaz, peki acil durum prosedürüne ne ihtiyacımız var?"
Lilienthal

2

Genel olarak, istisnalar olmadan önce yaptığımız gibi - eski "geri dönüş değeri yaklaşımını kontrol et". Bir tahsisatçı istisnalar kullanmazsa, nulltahsisat başarısız olduğunda genellikle geri döner . İyi yazılmış bir oyun bunu kontrol edecek ve durumu ne şekilde güvenli olursa olsun halledecektir. Bazen bu, oyunu sona erdirmek (örneğin std::terminate) veya en azından bilinen en son güvenli duruma geri dönmek anlamına gelir (örneğin , bir havuzdan tahsis ederken, güvensiz bir durumda olsa bile tüm havuzu güvenle elden çıkarabilirsiniz).

Çoğu oyun, böyle durumlarda bile istisnalar kullanır. Birisi "oyun kodunda istisnalar kullanmaktan kaçının" derken, genellikle demek istedikleri "sıradan akış kontrolü için değil, yalnızca istisnai durumlar için istisnalar kullanmaktır" dır. Bellek yetersizliği istisnasını yakalamak için yapılan kurulum ucuzdur - maliyet en fazla artış ve istisnayı ele almanın getirdiği komplikasyonlardır. Bunların hiçbiri tipik bir bellek dışı durum için çok önemlidir - neredeyse her zaman yine de sonlandırmak istersiniz.

Dikkat et, çoğu oyun sadece çökecek. Bu göründüğü kadar çılgınca değildir - genellikle bir hedef olarak bir miktar bellek kullanımınız vardır ve oyununuzun bu sınıra ulaşmadığından emin olun (örneğin, bir RTS oyunda bir birim sayımı sınırını kullanarak veya FPS'nin bir bölümündeki düşmanların miktarı). Yapmasanız bile, genellikle herhangi bir modern sistemde hafızanız tükenmez - örneğin sanal bir adres alanı (32 bit uygulamada) veya yığında bitirdiniz. İşletim sistemi zaten istediğiniz kadar belleğiniz olduğunu iddia ediyor - bu sanal belleğin sağladığı soyutlamalardan biri. Mesele şu ki, 256 MiB fiziksel RAM'iniz olması, uygulamanızın 4 GiB bellek kullanamayacağı anlamına gelmez. Bazı oyunlar, verilerinin hepsinin çok fazla olduğunu bile umursamaz.


1

Bir istisna yakalamak ve ne zaman ve istisna ortaya çıktığında karar vermek iki farklı şeydir.

Programınızın ihtiyaç duymadığı belleği boşaltmak için karmaşık bir mantığa ihtiyacınız var. Daha da kötüsü, çalışan başka bir program veya kütüphane hafızayı sızdırıyorsa, üzerinde hiçbir kontrol sizde olmaz

Nazikçe kapatmak için yapabileceğiniz tek iyi şey ve programların çoğunun yapmayı seçeceği şey. Programın tepkisiz kalmasına neden olacağından, bellekte boşalana kadar beklemeye bile karar veremezsiniz.


Söz konusu oyunlar OP'nin söylediği gibi kelimenin tam anlamıyla "istisnalar kullanmıyorlarsa", birini yakalayamaz, yükseltemez ya da işleyemezler. İstisnalar devre dışı bırakılırsa ve birisi bir tanesini atarsa, programın yerine çağırması gerekir std::terminate, o kadar. Ancak bu şartlar altında tahsisat, istisna atmak yerine boş gösterici döndürebilir ve ayrı olarak ele alınabilir.
underscore_d
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.