Pourquoi la gestion de la mémoire personnalisée est-elle nécessaire pour les actifs?

10

Presque toutes les ressources relatives à la programmation de jeux, en particulier les jeux 3D en monde ouvert, expliquent comment vous devez constamment décharger et recharger des ressources vers et depuis le disque, la mémoire système et la mémoire vidéo. Je peux comprendre cela sur les consoles, car elles ont des schémas de gestion de la mémoire très simples qui ne peuvent pas faire face à un débordement potentiel.

Cependant, sur PC, la situation est très différente. Il y a de la mémoire virtuelle fournie par le système d'exploitation pour la mémoire système et le pilote graphique gère l'échange entre le CPU et le GPU. Alors, pourquoi ne suffit-il pas de tout charger en même temps et de ne traiter que la prélecture et éventuellement de s'assurer qu'il n'y a pas de blocage pendant l'échange d'un actif requis?


Cela ne veut pas dire que tout est alloué naïvement en utilisant quelque chose comme malloc. Tout sera maintenu contigu et cohérent avec le cache. Il est sans doute plus facile de rendre votre accès mémoire efficace si vous n'avez pas à vous soucier de la pagination manuelle de toute façon ...


METTRE À JOUR:

Après avoir lu un peu les transferts de mémoire tampon asynchrones , j'ai l'idée que la façon dont le pilote graphique peut automatiquement paginer la mémoire en entrée et en sortie n'est pas optimale. Cela vaut-il également pour les ressources CPU; c'est-à-dire, est-il préférable de toujours gérer manuellement quand une ressource donnée doit être chargée et déchargée même en présence de mémoire virtuelle?

jmegaffin
la source
1
Vous supposez que le contenu de l'actif est stocké dans la mémoire système. Une grande partie de vos données sur les actifs seront stockées dans la mémoire du GPU, ce qui est beaucoup plus limité.
dadoo Games
En lisant la réponse ici, j'ai l'idée que les pilotes OpenGL gardent automatiquement tous les tampons / textures sur le CPU. Cependant, je peux voir pourquoi il pourrait être utile de spécifier ces transferts manuellement pour tirer parti des téléchargements asynchrones .
jmegaffin
Êtes-vous sûr que cela est pertinent pour votre projet de jeu? Je ne suis pas sûr de voir le défi technique, seulement la solution. Si vous n'êtes pas confronté à un défi technique, il est difficile d'adapter ou de comprendre une solution.
AturSams
Je me demande pourquoi les moteurs de jeux implémentent des systèmes de mise en cache d'actifs complexes alors que les systèmes d'exploitation / pilotes disposent déjà de systèmes de mémoire virtuelle. Cela me concerne parce que j'écris un jeu en monde ouvert où ces informations sont très importantes.
jmegaffin
Votre jeu souffre-t-il de problèmes de performances et l'outil de profilage montre que c'est à cause de l'accès à la mémoire? Le problème avec les jeux qui contiennent des niveaux ouverts est qu'en termes techniques, cela se traduit par beaucoup de données. Plus vous aurez de contrôle sur ces données, meilleures seront les performances. Pourquoi ne pas mettre en place le système le plus efficace pour gérer les données? Le développement de jeux est très compétitif et lorsque vous avez de l'argent pour des experts, vous ne laisserez aucun détail, cherchant à obtenir plus de détails et des images par seconde plus élevées.
AturSams du

Réponses:

16

Les jeux modernes en monde ouvert ne tiennent tout simplement pas en mémoire. Gardez à l'esprit que la plupart des jeux sont encore 32 bits en raison du nombre de joueurs avec des systèmes d'exploitation 32 bits, et un processus 32 bits ne peut au mieux avoir que 4 Go de mémoire adressée à la fois (indépendamment de la mémoire virtuelle), mais est réaliste limité à 2-3 Go. La fragmentation et la quantité réelle d'objets utilisables que vous pouvez avoir dans une mémoire à la fois sont un peu plus petites que le total des données dont vous avez besoin pour un grand environnement. Même sur un système d'exploitation 64 bits, vous devez souvent cibler des machines de faible spécification avec seulement 4 Go de mémoire pour garantir une compatibilité maximale avec l'utilisateur final. N'oublions pas les appareils mobiles, le matériel «sous-alimenté» comme la WiiU, etc. Les développeurs doivent viser bien plus que les grandes plates-formes de PC de jeu sophistiquées.

La mémoire virtuelle n'est pas une solution, d'abord parce qu'elle n'annule pas les limitations d'espace d'adressage et aussi parce qu'elle n'est pas optimale. Le système d'exploitation peut paginer les choses à des moments inopportuns ou de manière inopportune. Il s'agissait d'un problème traité par les systèmes d'exploitation lors de la mise en veille prolongée; paginer les processus sur le disque puis les paginer en arrière était considérablement plus lent dans certains cas que de demander à l'application de renvoyer explicitement la ressource. Vous pouvez toujours voir les problèmes aujourd'hui quand un système manque de mémoire, les pages sont paginées vers disque, et le système ne répond plus devient des choses essentielles nécessaires pour exécuter votre WM / explorer.exe obtenir paginé. La mémoire virtuelle était une solution mise au point il y a des décennies, où les systèmes avaient très peu de RAM et l'écart entre la mémoire et la vitesse du disque était beaucoup plus petit. Même aujourd'hui' Les SSD les plus rapides sont une infime fraction de la vitesse de la RAM bon marché / lente, et essayer de prétendre que vous pouvez utiliser votre disque comme RAM virtuelle n'est tout simplement plus la meilleure idée. C'est une époque où certaines personnes font le contraire et chargent des systèmes de fichiers sur des disques RAM; les contraintes qui ont conduit à la création de mémoire virtuelle ne sont plus d'actualité.

Même en dehors du problème de disque, la gestion des ressources personnalisées est toujours une grande partie du développement de jeux. Du débogage des crochets aux problèmes de fragmentation en passant par le streaming intelligent de ressources complexes, il ne suffit pas de prétendre que le monde entier est une boîte de bits infiniment grande.

Sean Middleditch
la source
Merci pour la réponse détaillée. Bien que je recherche toujours des informations sur la façon dont les pilotes GPU gèrent la mémoire virtuelle (entre la VRAM et la RAM système).
jmegaffin
@Boreal: mêmes problèmes. Remplacez simplement «RAM» par «VRAM» et «disk» par «CPU memory»
Sean Middleditch
@SeanMiddleditch +1 Belle réponse, "C'est une époque où certaines personnes font le contraire et chargent des systèmes de fichiers sur des disques RAM", voulez-vous dire des fichiers mappés en mémoire? De plus, ce que je comprends de votre réponse est que l'allocateur de mémoire personnalisé empêche le système d'exploitation de paginer la mémoire, n'est-ce pas le cas car la mémoire sera paginée autant que vous demanderez de la mémoire au noyau en utilisant brk () par exemple, comment la pagination sur PC est exactement empêchée à l'aide d'un allocateur de mémoire personnalisé?
concept3d
1
@ concept3d: pas de mappage de mémoire, mais des disques RAM littéraux. Vous pouvez créer un lecteur sauvegardé par la mémoire et non par le disque. Le gestionnaire de mémoire personnalisé n'empêche pas la pagination (une autre application pourrait utiliser toute la mémoire). La gestion intelligente des ressources (au niveau de la couche de gestion des objets / ressources) signifie simplement que vous libérez de la mémoire pour les objets dont vous n'avez plus besoin. Pensez aux caches de disque du système d'exploitation qu'il garde en mémoire
Sean Middleditch
6

Pour un jeu 32 bits, comme la plupart des jeux le sont pour diverses raisons, même un jeu fourni sur un DVD simple face (4,3 Go) a déjà beaucoup plus de contenu qui peut être inséré dans un espace d'adressage 32 bits. Et cela suppose que le contenu n'est pas compressé sur le disque, et de manière parfaitement optimale, chargez tout à la fois dans une approche d'espace d'adressage contiguë. De nombreux jeux sont désormais disponibles sur plusieurs DVD, dépassant facilement 10 Go de contenu. D'après mon expérience sur PC, une fois que votre espace d'adressage approche, les allocations de 2 Go commencent à échouer, et cela devient une limite stricte, quelle que soit la quantité de mémoire physique dont dispose l'utilisateur.

Si vous passez au 64 bits, en supposant que votre moteur le supporte, cette limite dure disparaît, pour être remplacée par une limite souple efficace - dès que l'échange de mémoire virtuelle commence à se produire, les performances du jeu chutent de façon inacceptable. Si le processus principal doit attendre que la mémoire soit paginée, la fréquence d'images saccadera et glitch. La mémoire virtuelle peut rendre cela transparent, mais cela ne le rend pas performant. Physiquement, il faut du temps pour récupérer cette mémoire à partir du disque, et pendant que vous attendez, votre jeu est au point mort. Bien qu'il soit possible de contourner le problème (avec une prélecture en arrière-plan des pages de mémoire dont vous savez que vous aurez bientôt besoin), c'est un processus difficile et peu fiable, et aura toujours des implications en termes de performances.

Les algorithmes du système d'exploitation pour décider des pages à échanger sur le disque n'ont aucune connaissance de votre jeu et de ce dont il aura probablement besoin ensuite. De plus, le système d'exploitation doit toujours prendre en charge d'autres applications fonctionnant simultanément avec votre jeu, ainsi que le système d'exploitation lui-même. Le fait de devoir bloquer pendant que les pages sont renvoyées à partir du disque est un énorme impact sur les performances, et peu importe que ce soit votre jeu, une autre application ou le système d'exploitation qui en découle, les performances du jeu en souffriront considérablement.

Ainsi, que la limite de mémoire soit douce ou dure, la mémoire est toujours limitée. Mais même si vous pouviez tout charger à la fois, sans atteindre une limite de performances, il y a toujours des raisons pour lesquelles vous ne voudriez pas:

  1. Votre jeu prend beaucoup plus de temps à charger et à atteindre un état interactif qu'il n'en a besoin, car il charge simplement tout au début et le maintient en permanence. Vous pouvez charger environ 150 Mo / s à partir d'un disque dur, et même le lecteur de DVD le plus rapide (24x) se charge à 33 Mo / s. Cela signifie que l'exemple de contenu de 4,3 Go de DVD prendra au moins 30 secondes à charger à partir du disque dur et plus de 133 secondes à charger à partir du DVD. Ce sont des temps de chargement trop longs.

  2. Votre jeu prend beaucoup plus de mémoire que ce qui est justifié. Si seulement 10% du contenu est visible à un moment donné, la détention du reste du résident est simplement du gaspillage et empêche l'utilisateur d'utiliser cette mémoire pour autre chose. Les utilisateurs ne pardonnent généralement pas les jeux qui nécessitent une quantité disproportionnée de mémoire pour fonctionner correctement.

La diffusion dynamique d'actifs à partir du disque, que ce soit en arrière-plan ou de manière synchrone pendant un écran de chargement, vous permet d'être beaucoup plus efficace dans votre utilisation de la mémoire, avec un effort négligeable et seulement un inconvénient mineur pour l'utilisateur. Mais c'est une optimisation, et comme toute autre optimisation, elle a des rendements décroissants plus vous essayez de l'appliquer. À un certain point, l'augmentation de l'empreinte mémoire pour garder quelque chose de résident est compensée par les avantages tirés de l'avoir là sans avoir à le charger. Mais jusqu'à ce que ce point soit atteint, il est préférable de ne charger que ce dont vous avez besoin, quand vous en avez besoin.

MrCranky
la source
1

Parlant de manière très générale et simpliste, et sans tenir compte des détails des implémentations de mémoire virtuelle, le développeur a toujours une connaissance prospective de l'implémentation de la machine virtuelle.

Le développeur peut toujours dire: "Je n'ai pas besoin de charger ce fichier audio pour le moment. La musique à l'intérieur n'est utilisée que pour le jeu sur écran." Et immédiatement après le jeu sur écran, le développeur peut dire: "Je n'ai plus besoin de ce clip audio dans la mémoire physique. Il n'est utilisé que pour ce jeu sur écran."

L'OS n'a pas une telle prévoyance. Il pourrait être en mesure de comprendre, de nombreuses erreurs de page plus tard, que certains clips audio ne sont plus nécessaires dans la mémoire physique car ils n'ont pas été consultés depuis longtemps. Mais transformer la prospective en rétrospective se traduit par de nombreux défauts de page, et de nombreux défauts de page se traduisent par des hoquets dans les taux de trame dans un logiciel aussi critique en temps qu'un jeu vidéo. Là, la clairvoyance du développeur aide vraiment si vous voulez éviter de tels hoquets.

Et cela s'applique conceptuellement indépendamment du matériel et des logiciels. En supposant que la pagination en mémoire coûte cher, la prévoyance du développeur contribuera toujours à réduire ces dépenses.

De manière encore plus large, il existe un cycle sans fin entre concepteur de matériel, concepteur de compilateur, concepteur de système d'exploitation / pilote et développeur d'application. Les développeurs de matériel / compilateur / OS / pilote essaient souvent d'implémenter des optimisations pour accélérer votre application moyenne en fonction de ses modèles d'accès à la mémoire habituels, et peut-être parfois avec l'espoir du genre: "Les gens devraient simplement être en mesure d'écrire du code comme ils le souhaitent et devrait être rapide. "Mais s'il y avait une idée de ce type, il échoue généralement pour les domaines critiques pour les performances, car les développeurs critiques pour les performances commencent alors à apprendre les détails complexes de leur compilateur, matériel, système d'exploitation, pilotes, etc. et commencent à écrire du code spécifiquement conçu pour exploiter cela autant que possible pour écrire le code le plus rapide possible (comme les pré-récupérations, la division de champ chaud / froid, les SoAs, etc. pour le code compatible avec le cache). Et c'est comme un jeu qui ne finit jamais. Ces choses ne sont jamais traitées comme des boîtes noires dans les domaines critiques pour les performances, car les développeurs sont en compétition pour les performances.

Personnellement, je souhaite un peu que la mémoire virtuelle n'existe pas car elle ajoute une couche supplémentaire d'imprévisibilité des performances d'une manière qui a tendance à être trop extrême et à entraîner beaucoup trop de pénalités de performance lorsque les choses vont vraiment au sud jusqu'au point d' inutilisabilité. J'ai parfois rencontré des cas où j'ai utilisé une application où j'ai tapé un ou deux chiffres supplémentaires par accident lorsqu'il était ivre dans un champ de saisie, ce qui a ensuite épuisé la mémoire physique si rapidement d'une manière qui a amené le système d'exploitation à une analyse où je ne pouvais pas '' Je n'ai même plus cliqué sur le bouton Annuler de la barre de progression et j'ai dû attendre 10 minutes tout en bloquant Ctrl + Alt + Suppr pour tuer un processus et me maudire tout en renversant ma boisson pour revenir à un point où les choses sont à nouveau utilisables, et que était malgré le fichier de page étant stocké sur un SSD. Dans ces cas, j'aurais plutôt préféré une erreur de "mémoire insuffisante" ou quelque chose, à quel point je pourrais fermer certains de mes 17 onglets de porno (c'est bon, je marque mes favoris de toute façon) pour libérer de la mémoire et ensuite aller immédiatement reprendre mes affaires.


la source