Wie gehen C ++ - Spiele mit Speicherzuordnungsfehlern um?


23

Mir sind einige Spiele bekannt, die in C ++ geschrieben sind, aber keine Ausnahmen verwenden. std::bad_allocWie gehen diese Spiele mit einem solchen Fehler um, da die Behandlung von Speicherzuweisungsfehlern in C ++ im Allgemeinen um die Ausnahme herum aufgebaut ist ?

Stürzen sie einfach ab, oder gibt es eine andere Möglichkeit, mit einem Fehler aufgrund von Speichermangel umzugehen und ihn zu beheben?


1
Beachten Sie, dass es bestimmte Umgebungen / Betriebssysteme gibt, in denen die Zuweisung den Anspruch auf Erfolg erhebt. Wenn Sie jedoch versuchen, den Speicher zu verwenden, stürzt Ihr (oder ein anderes) Programm ab
PlasmaHH

6
Wenn die Zuordnung während eines Spiels fehlschlägt, werden Sie von Quake 3 mit einer Fehlermeldung zurück zum Menü geführt. Ich glaube, dies wird durch den Pool-Allokator von Quake 3 ermöglicht, der einfach den gesamten Pool löschen und sicher zum Menü zurückkehren kann, wenn der Pool leer wird.
Dietrich Epp

16
Normalerweise durch Absturz.
user253751

1
Wenn Ausnahmen wirklich deaktiviert sind, muss das Programm stattdessen aufrufen std::terminate, und das war's. Unter derselben Einschränkung kann die Zuweisung jedoch einen Nullzeiger zurückgeben, anstatt eine Ausnahme auszulösen, und dieses Ergebnis kann separat überprüft und behandelt werden.
Underscore_d

2
In C ++ können Sie sagen ClassName variableName = new(nothrow) ClassName();( Klassennamen, Variablennamen usw. offensichtlich ersetzen ). Wenn die Zuordnung fehlschlägt, können Sie dies erkennen, indem Sie sagen, if(!variableName)dass der Fehler ohne einen Try-Catch-Ausnahmeblock behandelt werden kann. Ebenso, wenn der Speicher eine Funktion wie zugeteilt verwendet malloc(), calloc()usw., dann können Ausfälle zuzuteilen detektierenden Verwendung derselben if(!variableName)Methode ohne eine try-catch zu benötigen. Was den Umgang der Spiele mit diesen Fehlern angeht, ist es nun an den Spielentwicklern zu entscheiden, ob sie abstürzen oder nicht.
Spencer D

Antworten:


63

Wie bei allen durchschnittlichen Programmen: Sie tun es nicht. *

Für die meisten Anwendungen besteht keine Kundenerwartung, dass sie weiterarbeiten, sobald der Speicher voll ist. Alle Spiele fallen unter diese "meisten Anwendungen". Es macht keinen Sinn, Zeit und Geld für die Bearbeitung eines Edge-Falls zu investieren, von dem der Kunde nicht erwartet, dass er funktioniert.

Die Frage ähnelt der folgenden:

  • Wie installiere ich ein Spiel, wenn die Festplatte voll ist?
  • Wie läuft das Spiel auf einem PC mit hoher Geschwindigkeit unter den Mindestanforderungen?

Die Antwort ist die gleiche: Dies sind die Probleme der Benutzer. Das Spiel ist mir egal.


* Tatsächlich führen sie normalerweise einen High-Level-Catch der Ausnahme durch und verwenden zu Beginn des Spiels vorab zugewiesenen Speicher, um zu versuchen, das Ereignis vor dem Absturz / Beenden zu protokollieren. Das Protokoll ermöglicht dem Kundensupport, weniger Zeit für das Problem zu verschwenden.


2
Informationen zum Vorbelegen von Speicher für die Protokollierung usw. im Falle eines Speicherreservierungsfehlers: stackoverflow.com/questions/7749066/…
bwDraco

23

Typischerweise passiert so ein Szenario nie.

Erstens bedeutet virtueller Speicher auf modernen Betriebssystemen, dass es im normalen Betrieb sowieso sehr unwahrscheinlich ist. es sei denn, Sie haben einen außer Kontrolle geratenen Zuweisungsfehler, das Spiel weist Speicher aus dem virtuellen Adressraum des Betriebssystems zu und das Betriebssystem kümmert sich um das Ein- und Auslagern.

Das ist alles in Ordnung und gut, aber nicht wirklich für Konsolen oder ältere Betriebssysteme. Zweitens führen Spiele mit Standardbibliothekszuweisern ohnehin nicht einmal viele kleine dynamische Zuweisungen durch. Stattdessen reservieren sie einen großen Speicherpool einmalig beim Start und greifen auf alle erforderlichen Laufzeitzuordnungen zurück (z. B. durch Verwendung von C ++, das neu platziert wird, oder durch Schreiben eines eigenen Speicherverwaltungssystems darauf) oben drauf).

Dies schützt auch vor Speicherverlusten, da ein Spiel nicht nur die einzelnen Zuordnungen nachverfolgen und abrechnen muss, sondern auch den gesamten Pool wegwirft, um Speicherplatz freizugeben.

Und drittens legen Spiele immer eine Mindestspezifikation fest und budgetieren ihren Speicherverbrauch darin. Wenn für ein Spiel 1 GB RAM erforderlich ist, bedeutet dies, dass es sich niemals Sorgen machen muss, dass der Arbeitsspeicher knapp wird, solange die Speichernutzung 1 GB nicht überschreitet.


3
"Stattdessen wird ein großer Speicherpool nur einmalig beim Start zugewiesen und auf alle erforderlichen Laufzeitzuweisungen zurückgegriffen" - und was passiert Ihrer Meinung nach, wenn der Pool voll ist?
user253751

@immibis - siehe mein dritter Punkt bitte.
Maximus Minimus

2
@immibis Du meinst ... was machen sie, wenn der Pool leer ist? Im Gegensatz zum Systemspeicher wird die Größe und Nutzung des Pools vollständig von der Anwendung gesteuert. Daher kann der Pool nur dann leer werden, wenn die Anwendung einen Fehler aufweist.
David Schwartz

@DavidSchwartz Oder es sei denn, der Kernel verwendet Memory Overcommit. Linux macht das. Selbst wenn die Komprimierung von Auslagerungsdateien über zswap oder zram aktiviert ist, hilft es nicht, Ihren Pool auf Null zu setzen.
Damian Yerrick

1
Dies scheint nicht die eigentliche Frage zu beantworten, sondern besagt etwas Ähnliches wie "Dieses Schiff ist unsinkbar. Wofür brauchen wir also ein Notfallverfahren?"
Lilienthal

2

Nun, hauptsächlich so, wie wir es gemacht haben, bevor es Ausnahmen gab - den alten "Check the Return Value Approach". Wenn ein Allokator keine Ausnahmen verwendet, wird er normalerweise zurückgegeben, nullwenn eine Allokation fehlschlägt. Ein gut geschriebenes Spiel prüft dies und geht sicher mit der Situation um. Manchmal bedeutet dies, das Spiel zu beenden (z. B. std::terminate) oder zumindest zum letzten bekannten sicheren Zustand zurückzukehren (z. B. können Sie den gesamten Pool sicher entsorgen, auch wenn er sich in einem unsicheren Zustand befindet).

Viele Spiele verwenden auch dann noch Ausnahmen für solche Fälle. Wenn jemand sagt "Vermeiden Sie die Verwendung von Ausnahmen im Spielcode", bedeutet dies normalerweise "Verwenden Sie Ausnahmen nur für wirklich außergewöhnliche Fälle, nicht für die weltliche Ablaufsteuerung". Das Setup für das Abfangen einer Ausnahmebedingung aufgrund unzureichenden Arbeitsspeichers ist günstig - die Kosten sind hauptsächlich im Wurf und die Komplikationen bei der Behandlung der Ausnahmebedingung. Beides ist in einem typischen Fall von Speichermangel nicht sehr wichtig - Sie möchten sowieso fast immer kündigen.

Wohlgemerkt, die meisten Spiele werden einfach abstürzen. Dies ist nicht so verrückt, wie es sich anhört - Sie haben normalerweise eine gewisse Speichernutzung als Ziel und stellen sicher, dass Ihr Spiel diese Grenze nicht erreicht (z. B. indem Sie in einem RTS-Spiel eine Begrenzung für die Einheitenzahl verwenden oder die Begrenzung der Anzahl der Feinde in einem Abschnitt eines FPS). Selbst wenn dies nicht der Fall ist, wird auf einem einigermaßen modernen System in der Regel nicht genügend Arbeitsspeicher zur Verfügung stehen - beispielsweise nicht genügend virtueller Adressraum (in einer 32-Bit-Anwendung) oder nicht genügend Stapelspeicher. Das Betriebssystem gibt bereits vor, dass Sie über so viel Speicher verfügen, wie Sie benötigen - dies ist eine der Abstraktionen, die der virtuelle Speicher bietet. Nur weil Sie über 256 MB physischen Arbeitsspeicher verfügen, bedeutet dies nicht, dass Ihre Anwendung nicht 4 GB Arbeitsspeicher verwenden kann. Einige Spiele stören sich vielleicht gar nicht daran, dass all ihre Daten nicht vorhanden sind.


1

Das Abfangen einer Ausnahme und die Entscheidung, was zu tun ist, wenn eine Ausnahme ausgelöst wird, sind zwei verschiedene Dinge.

Sie benötigen eine komplexe Logik, um Speicher freizugeben, der von Ihrem Programm nicht benötigt wird. Schlimmer noch, wenn ein anderes laufendes Programm oder eine andere Bibliothek den Speicher verliert, haben Sie keine Kontrolle darüber

Es ist nur gut, dass Sie es schaffen, ordnungsgemäß herunterzufahren, und genau das werden die meisten Programme tun. Sie können nicht einmal warten, bis Speicher verfügbar ist, da Ihr Programm sonst nicht mehr reagiert.


Wenn die fraglichen Spiele buchstäblich "keine Ausnahmen verwenden", wie das OP sagte, dann können sie keine fangen, erhöhen oder verarbeiten. Wenn Ausnahmen deaktiviert sind und jemand eine auslöst, muss das Programm stattdessen aufrufen std::terminate, und das wars. Unter solchen Bedingungen kann die Zuweisung jedoch einen Nullzeiger zurückgeben, anstatt eine Ausnahme auszulösen, und dies kann separat behandelt werden.
Underscore_d
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.