Cela peut être facile pour les jeux avec une portée bien définie, mais la question concerne les jeux sandbox, où le joueur est autorisé à créer et à construire n'importe quoi .
Techniques possibles:
- Utilisez des pools de mémoire avec limite supérieure.
- Supprimez périodiquement les objets dont vous n'avez plus besoin.
- Allouez une quantité supplémentaire de mémoire au début afin qu'elle puisse être libérée plus tard en tant que mécanisme de récupération. Je dirais environ 2 à 4 Mo.
Cela est plus susceptible de se produire dans les plates-formes mobiles / consoles où la mémoire est généralement limitée contrairement à votre PC de 16 Go. Je suppose que vous avez un contrôle total sur l'allocation / désallocation de mémoire et aucune collecte de déchets impliquée. C'est pourquoi je marque cela en C ++.
Veuillez noter que je ne parle pas de l'élément efficace C ++ 7 "Soyez prêt pour les conditions de mémoire insuffisante" , même s'il est pertinent, j'aimerais voir une réponse plus liée au développement de jeux, où vous avez généralement plus de contrôle sur ce qui est événement.
Pour résumer la question, comment vous préparez-vous aux conditions de mémoire insuffisante pour les jeux sandbox, lorsque vous ciblez une plate-forme avec une console mémoire / mobile limitée?
la source
Réponses:
En règle générale, vous ne gérez pas la mémoire insuffisante. La seule option sensée dans un logiciel aussi grand et complexe qu'un jeu est de simplement planter / affirmer / terminer dans votre allocateur de mémoire dès que possible (en particulier dans les versions de débogage). Les conditions de mémoire insuffisante sont testées et gérées dans certains logiciels système de base ou logiciels de serveur dans certains cas, mais généralement pas ailleurs.
Lorsque vous avez un plafond de mémoire supérieur, assurez-vous simplement de ne jamais avoir besoin de plus que cette quantité de mémoire. Vous pouvez conserver un nombre maximum de PNJ autorisés à la fois, par exemple, et simplement arrêter de faire apparaître de nouveaux PNJ non essentiels une fois ce plafond atteint. Pour les PNJ essentiels, vous pouvez soit les faire remplacer les non-essentiels, soit avoir un pool / cap séparé pour les PNJ essentiels que vos concepteurs savent concevoir (par exemple, si vous ne pouvez avoir que 3 PNJ essentiels, les concepteurs n'en mettront pas plus de 3 dans une zone / un morceau - de bons outils aideront les concepteurs à le faire correctement et les tests sont bien sûr essentiels).
Un très bon système de streaming est également important, en particulier pour les jeux sandbox. Vous n'avez pas besoin de garder tous les PNJ et objets en mémoire. Au fur et à mesure que vous vous déplacez à travers des morceaux du monde, de nouveaux morceaux seront diffusés et de vieux morceaux diffusés. Ceux-ci incluront généralement des PNJ et des objets ainsi que du terrain. Les limites de conception et d'ingénierie sur les limites des objets doivent être définies en gardant ce système à l'esprit, sachant qu'au plus X anciens morceaux seront conservés et chargés de manière proactive Y de nouveaux morceaux seront chargés, de sorte que le jeu doit avoir de l'espace pour tout garder les données de X + Y + 1 morceaux en mémoire.
Certains jeux tentent de gérer les situations de mémoire insuffisante avec une approche en deux passes. En gardant à l'esprit que la plupart des jeux ont beaucoup de données mises en cache techniquement inutiles (par exemple, les anciens morceaux mentionnés ci-dessus) et une allocation de mémoire pourrait faire quelque chose comme:
Il s'agit d'une mesure de dernier recours pour faire face à des situations inattendues dans la version, mais pendant le débogage et les tests, vous devriez probablement immédiatement planter. Vous ne voulez pas avoir à vous fier à ce genre de choses (surtout parce que le vidage des caches peut avoir de graves conséquences sur les performances).
Vous pouvez également envisager de vider des copies haute résolution de certaines données, par exemple, vous pouvez vider les niveaux de textures mipmap à plus haute résolution si vous manquez de mémoire GPU (ou de toute mémoire dans une architecture à mémoire partagée). Cela nécessite généralement beaucoup de travail architectural pour en valoir la peine.
Notez que certains jeux sandbox très illimités peuvent être assez facilement simplement plantés, même sur PC (rappelez-vous que les applications 32 bits courantes ont une limite de 2-3 Go d'espace d'adressage même si vous avez un PC avec 128 Go de RAM; un 64- le système d'exploitation et le matériel bit permettent à plus d'applications 32 bits de s'exécuter simultanément mais ne peuvent rien faire pour qu'un binaire 32 bits ait un espace d'adressage plus grand). En fin de compte, soit vous avez un monde de jeu très flexible qui aura besoin d'espace mémoire illimité pour fonctionner dans tous les cas, soit vous avez un monde très limité et contrôlé qui fonctionne toujours parfaitement dans la mémoire limitée (ou quelque chose entre les deux).
la source
L'application est généralement testée sur la plate-forme ciblée avec les pires scénarios et vous serez toujours prêt pour la plate-forme que vous ciblez. Idéalement, l'application ne devrait jamais planter, mais à part l'optimisation pour des appareils spécifiques, il y a peu de choix lorsque vous êtes confronté à un avertissement de mémoire insuffisante.
La meilleure pratique est d'avoir des pools préalloués et le jeu utilise dès le début toute la mémoire nécessaire. Si votre jeu a un maximum de 100 unités, alors ayez un pool de 100 unités et c'est tout. Si 100 unités dépassent les exigences mem pour un appareil ciblé, vous pouvez optimiser l'unité pour utiliser moins de mémoire ou modifier la conception à un maximum de 90 unités. Il ne devrait pas y avoir de cas où vous pouvez construire des choses illimitées, il devrait toujours y avoir une limite. Il serait très mauvais pour un jeu sandbox d'utiliser
new
pour chaque instance car vous ne pouvez jamais prédire l'utilisation de mem et un crash est bien pire qu'une limitation.De plus, la conception du jeu doit toujours avoir à l'esprit les appareils les plus bas car si vous basez votre conception avec des choses "illimitées", il sera beaucoup plus difficile de résoudre les problèmes de mémoire ou de modifier la conception plus tard.
la source
Eh bien, vous pouvez allouer environ 16 Mio (juste pour être sûr à 100%) au démarrage ou même
.bss
au moment de la compilation, et utiliser un "allocateur sûr", avec une signature commeinline __attribute__((force_inline)) void* alloc(size_t size)
(__attribute__((force_inline))
est un GCC /mingw-w64
attribut qui force l'inclusion de sections de code critiques même si les optimisations sont désactivées, même si elles devraient être activées pour les jeux) au lieu demalloc
cela essaievoid* result = malloc(size)
et si cela échoue, supprimez les caches, libérez la mémoire de rechange (ou dites à un autre code d'utiliser la.bss
chose mais cela est hors de portée pour cette réponse) et vider les données non enregistrées (enregistrez le monde sur le disque, si vous utilisez un concept de morceaux de type Minecraft, appelez quelque chose commesaveAllModifiedChunks()
). Ensuite, simalloc(16777216)
(l'allocation de ces 16 Mio à nouveau) échoue (à nouveau, remplacez par analogique pour.bss
), mettez fin au jeu et affichezMessageBox(NULL, "*game name* couldn't continue because of lack of free memory, but your world was safely saved. Try closing background applications and restarting the game", "*Game name*: out of memory", MB_ICONERROR)
ou une alternative spécifique à la plate-forme. Mettre tous ensemble:Vous pouvez utiliser une solution similaire avec
std::set_new_handler(myHandler)
oùmyHandler
estvoid myHandler(void)
appelé en cas d'new
échec:la source