Je connais plusieurs jeux qui sont écrits en C ++ mais n'utilisent pas d'exceptions. Étant donné que la gestion des échecs d'allocation de mémoire en C ++ est généralement construite autour de l' std::bad_alloc
exception, comment ces jeux gèrent-ils un tel échec?
Se bloquent-ils simplement ou existe-t-il un autre moyen de gérer et de récupérer après une erreur de mémoire insuffisante?
c++
resource-management
memory
user200783
la source
la source
std::terminate
, et c'est tout. Mais sous la même restriction, l'allocation peut renvoyer un pointeur nul au lieu de lever une exception, et ce résultat peut être vérifié et géré séparément.ClassName variableName = new(nothrow) ClassName();
( évidemment en remplaçant le nom de classe, le nom de variable, etc. ) Ensuite, si l'allocation échoue, vous pouvez la détecter en disant deif(!variableName)
permettre à l'erreur d'être gérée sans bloc d'exception try-catch. De même, si la mémoire est allouée à l' aide d' une fonction commemalloc()
,calloc()
, etc., puis les échecs d'affecter peut être détectée en utilisant la mêmeif(!variableName)
méthode sans avoir besoin d' un try-catch. Quant à la façon dont les jeux gèrent ces erreurs, eh bien, à ce stade, il appartient aux développeurs du jeu de décider s'il se bloque ou non.Réponses:
Identique à tous les programmes moyens: ils ne le font pas. *
Pour la plupart des applications, les clients ne s'attendent pas à ce qu'ils continuent de fonctionner une fois la mémoire épuisée. Tous les jeux relèvent de la "plupart des applications". Dépenser du temps et de l'argent pour travailler sur un boîtier de pointe que le client ne s'attend pas à travailler n'a pas de sens.
La question est similaire à la suivante:
La réponse est la même: ce sont les problèmes des utilisateurs. Le jeu s'en fiche.
* En fait, ils font généralement une capture de haut niveau de l'exception et utilisent la mémoire qui a été pré-allouée au début du jeu afin d'essayer de consigner l'événement avant de planter / terminer. Le journal permet ensuite au support client de perdre moins de temps sur le problème.
la source
En règle générale, ce genre de scénario ne se produit jamais.
Premièrement, la mémoire virtuelle sur les systèmes d'exploitation modernes signifie qu'il est peu probable qu'il se produise de toute façon en fonctionnement normal; sauf si vous avez un bogue d'allocation galopant, le jeu allouera de la mémoire à partir de l'espace d'adressage virtuel du système d'exploitation et le système d'exploitation s'occupera de la pagination à l'intérieur et à l'extérieur.
C'est bien beau, mais cela ne s'applique pas vraiment aux consoles ou aux anciens systèmes d'exploitation, donc deuxièmement, les jeux ne font même pas beaucoup de petites allocations dynamiques en utilisant des allocateurs de bibliothèque standard de toute façon. Au lieu de cela, ils vont allouer un grand pool de mémoire une seule fois au démarrage et tirer de ce pool pour toutes les allocations d'exécution qui sont nécessaires (par exemple en utilisant le placement C ++ nouveau ou en écrivant leur propre système de gestion de la mémoire sur dessus).
Cela protège également contre les fuites de mémoire, car plutôt que d'avoir à suivre et à rendre compte de chaque petite allocation individuelle, un jeu peut simplement jeter tout le pool pour récupérer de la mémoire.
Et troisièmement, les jeux définiront toujours une spécification minimale et budgétiseront leur utilisation de mémoire à l'intérieur de cela. Donc, si un jeu est spécifié pour nécessiter 1 Go de RAM, cela signifie que tant que son utilisation de la mémoire ne dépasse jamais 1 Go, il n'a jamais à se soucier de manquer de RAM.
la source
Eh bien, principalement, de la même manière que nous le faisions avant que des exceptions n'existent - l'ancienne «approche de la valeur de retour». Si un allocateur n'utilise pas d'exceptions, il revient généralement en
null
cas d'échec d'une allocation. Un jeu bien écrit vérifiera cela et gérera la situation de quelque manière que ce soit en toute sécurité. Parfois, cela signifie mettre fin au jeu (par exemplestd::terminate
) ou au moins revenir au dernier état sûr connu (par exemple, lorsque vous allouez à partir d'un pool, vous pouvez éliminer en toute sécurité le pool entier même lorsqu'il est dans un état dangereux).De nombreux jeux utilisent des exceptions pour des cas comme celui-là même alors. Quand quelqu'un dit "éviter d'utiliser des exceptions dans le code du jeu", ce qu'il veut généralement dire est "n'utiliser des exceptions que pour des cas vraiment exceptionnels, pas pour un contrôle de flux banal". La configuration pour intercepter une exception de mémoire insuffisante est bon marché - le coût est principalement dans le lancer et les complications que vous obtenez avec la gestion de l'exception. Aucun de ces éléments n'est très important dans un cas typique de mémoire insuffisante - vous voulez presque toujours terminer de toute façon.
Attention, la plupart des jeux plantent. Ce n'est pas aussi fou que cela puisse paraître - vous avez généralement une certaine utilisation de la mémoire comme cible, et assurez-vous que votre jeu n'atteint pas cette limite (par exemple, en utilisant une limite de nombre d'unités dans un jeu RTS, ou en limitant la quantité d'ennemis dans une section d'un FPS). Même si vous ne le faites pas, vous ne manquez généralement pas de mémoire sur un système raisonnablement moderne - vous manquez d'espace d'adressage virtuel (dans une application 32 bits) ou de la pile, par exemple. Le système d'exploitation prétend déjà que vous avez autant de mémoire que vous demandez - c'est l'une des abstractions que la mémoire virtuelle fournit. Le fait est que le fait que vous ayez 256 Mo de RAM physique ne signifie pas que votre application ne peut pas utiliser 4 Go de mémoire. Certains jeux peuvent même ne pas trop se soucier du fait que toutes leurs données ne sont pas
la source
Attraper une exception et décider de faire quoi quand une exception est levée sont deux choses différentes.
Vous devez disposer d'une logique complexe pour libérer de la mémoire dont votre programme n'a pas besoin. Pire encore, si un autre programme ou bibliothèque en cours d'exécution fuit la mémoire, vous n'avez aucun contrôle dessus
Seule bonne chose, vous pouvez le faire pour arrêter avec élégance et c'est ce que la plupart des programmes choisissent de faire. Vous ne pouvez même pas décider d'attendre que la mémoire soit disponible car cela rendra votre programme insensible.
la source
std::terminate
, et c'est tout. Mais dans de telles conditions, l'allocation peut renvoyer un pointeur nul au lieu de lever une exception, et cela peut être géré séparément.