Enfreindre les règles de la collecte des ordures Unity

Il était une fois un programmeur de jeux d'unité appelé Lancelot. Un très passionné, je dirais. Il ne le savait pas encore, mais il finirait par faire face au côté le plus sombre de la collecte des ordures Unity.

image

Lancelot était toujours à la recherche de titres de plus en plus gros sur lesquels travailler. Et donc il a travaillé dur pour avoir sa grande chance dans l'industrie des jeux.

Ce n'était pas facile, il le savait.

Ces places dans l'industrie du jeu étaient et sont encore réservées à une petite minorité de programmeurs de jeux. Et il n'était pas sûr qu'il serait aux normes, de toute façon.

Mais il a persisté et a continué à affiner ses compétences en programmation.

Lancelot a commencé à travailler sur les petits jeux. Peut-être qu'à un moment donné, il aurait la grande chance qu'il cherchait, pensa-t-il.

Des années ont passé jusqu'à ce qu'il ait l'opportunité qu'il attendait. On lui a demandé de porter un gros jeu VR sur une plateforme mobile. Aussi enthousiaste que Lancelot, il ne pouvait s'empêcher de se demander s'il était assez bon pour la tâche. C'était intimidant, mais il a accepté le défi. Il savait qu'il ne pouvait que grandir avec ça.

La plus grande préoccupation de Lancelot était la nécessité d'améliorer massivement les performances du jeu. C'était en fait un double défi. Il a dû améliorer les performances de 20% pour une plateforme nettement moins puissante .

Après des mois de travail ininterrompu, il a finalement réussi à optimiser suffisamment le jeu pour avoir une base de référence solide comme le roc.

Cependant, un problème inattendu était imminent ...

Le profileur d'unité lui a révélé une baisse significative de la fréquence d'images toutes les quelques secondes. Et cela l'inquiétait car cela ne lui permettrait pas d'expédier le match. La sortie du jeu était en danger. Cela le rendait vraiment mal à l'aise.

Sur la base de son expérience antérieure, Lancelot a rapidement soupçonné le ramasse - miettes . Après tout, il savait que l'allocation trop fréquente de mémoire temporaire dans le jeu pouvait entraîner ces pics de performances. Tout comme la poubelle dans la cuisine de chacun, vous savez qu'il est temps de la nettoyer lorsqu'elle atteint 80% de sa capacité.

Et donc il a passé des jours à combattre les allocations de mémoire gênantes. Il a effectué tous les types d'optimisations auxquels il pouvait penser. Pools d'objets, mise en cache des données, optimisations de la structure des données ...

Passer ces jours à l'optimiser lui a permis de prendre un peu d'avance dans le parcours de la performance. Lancelot était fier de son travail, mais ses préoccupations n'ont fait que grandir quand il a vu le ramasse-miettes toujours en marche toutes les 15 secondes.

Jouer au jeu en VR avec ces baisses de performances rendrait les gens pâles.

"Comment est-ce possible?", Se demanda-t-il.

Avec plus de patience et de fouilles, Lancelot a découvert une deuxième source d'allocations de mémoire qu'il n'avait jamais vue auparavant. Cela s'est passé dans une bibliothèque tierce .

Il jeta un coup d'œil et se rendit rapidement compte qu'il était dans la pire position de tous les temps: cette bibliothèque était une source fermée. Non seulement cela, il a également essayé d'utiliser le récupérateur incrémentiel d'Unity, mais il ne pouvait pas se permettre de payer son prix de performance.

Lancelot manquait d'options.

Il se sentait désespéré mais a réussi à garder son calme. Il a été dans des situations pires après tout.

Il pourrait faire de l'ingénierie inverse de la bibliothèque et faire lui-même les optimisations d'allocation de mémoire. Le problème était que la licence interdisait de telles choses. Et il était trop jeune pour aller en prison.

La deuxième option qu'il a envisagée était de pré-allouer beaucoup de mémoire sur le tas. Il savait que l'unité déclenchait le processus de collecte des ordures lorsque l'utilisation du tas atteignait un certain pourcentage. L'augmentation du tas devrait donc lui donner plus de temps entre les récupérations.

Malheureusement, ce n'était toujours pas suffisant.

Il avait lentement l'impression qu'il n'avait aucun contrôle sur la situation. C'était difficile, mais encore une fois, il a persisté .

Lancelot a donc eu une idée folle . Et s'il désactivait complètement la collecte des ordures? Etait-ce même possible? Il sentait dans ses os à quel point une telle idée était risquée. Il ne voulait pas ajouter la possibilité que le jeu plante à des moments imprévisibles. La dernière fois qu'il a vérifié, ce n'était pas amusant pour les joueurs. Peut-être que les temps ont changé, mais mieux vaut prévenir que guérir.

En plus de cela, il craignait de retarder la sortie du jeu. Il ne voulait pas que ses joueurs ratent ce titre pour Noël. Il se souvenait du plaisir qu'il avait eu à jouer à EverQuest pendant ces vacances. Il ne retirerait pas cela aux joueurs.

Arrivé à ce point, il n'avait d'autre choix que de désactiver le ramasse-miettes.

Il est passé en mode recherche et a découvert qu'il pouvait en effet désactiver manuellement la collecte des ordures . Il a mené des dizaines d'expériences pour voir combien de temps le jeu durerait sans manquer de mémoire. Il a fait toutes sortes de tests pour stresser le système. Cliquer partout, marcher et sauter, basculer entre différentes applications.

Des chiffres ont commencé à arriver dans sa feuille de calcul: 25 minutes, 28 minutes, 30 minutes ... Il a également noté comment l'utilisation du tas augmentait avec le temps pour être certain de ne jamais dépasser un budget sûr.

Avec ces chiffres, Lancelot a établi une marge de sécurité généreuse et a préparé un prototype . Il exécutait la collecte des ordures manuellement pendant le chargement des écrans et toutes les quelques minutes.

Il avait de nouveau de l'espoir.

Il a poliment demandé à QA de parcourir le jeu des dizaines de fois.

La mémoire était toujours dans le budget. Aucun plantage. Pas d'effets secondaires.

Ce long voyage l'a amené au point où il a pu expédier le jeu.

Et devinez quoi? Des centaines de joueurs en profitent désormais pendant la période de Noël.

Au début, il n'était pas à l'aise avec cette solution. C'était une décision risquée et il le savait. Mais il a réussi à le retirer.

Lancelot a appris à être à l'aise avec l' inconfortable . Il a appris à être plus pragmatique . Parce qu'il y a des moments où un programmeur doit l'être.

Est-ce que quelque chose de l'histoire vous dit quelque chose? Si oui, votre intuition a probablement raison.

Ce programmeur était moi.

Pour les moments où vous en avez besoin, voici comment vous pouvez gérer le garbage collector:

Cet extrait de code vous montre comment désactiver les récupérations automatiques de place. Il exécute le processus GC manuellement toutes les minutes et éventuellement pendant les transitions d'écran (fondu au noir).

Soyez conscient de ses effets secondaires possibles:

  • Crashes : si vous ne jouez pas suffisamment en sécurité, vous manquerez de mémoire. Pire, le système d'exploitation peut tuer votre jeu lorsque vous basculez entre les applications
  • Temps de collecte des ordures plus longs : augmenter le tas ralentira les futures collectes de déchets

Si vous devez produire de grandes quantités de déchets, voici une méthode simple qui fonctionnera:

public class GenerousGarbageCreator : MonoBehaviour { [SerializeField] private int garbageCreationRate = 1024; private static int[] _garbage; void Update() { _garbage = new int[garbageCreationRate]; } } 

Voici ce que vous obtiendrez dans le profileur:

image
Unity Garbage Collection: déclenchement manuel basé sur le temps

Là, vous voyez une utilisation croissante de la mémoire. L'utilisation croissante du tas est mise en évidence comme "mono". Heureusement pour nous, nous exécutons le ramasse-miettes manuel toutes les 3 secondes.

Vous pouvez clairement voir ce cycle de génération de génération de déchets dans le graphique du profileur. Pour les développeurs de jeux qui ont étudié la physique, vous pourriez le reconnaître comme une forme d'onde en dents de scie.

Si vous voulez le code source de ce projet, vous savez où le trouver (spoiler: ici).

Pour des optimisations de mémoire plus générales, vous pourriez être intéressé par Unity Addressables. Avec les adressables, vous pouvez réduire votre utilisation totale de la mémoire afin de pouvoir déclencher des récupérations moins fréquentes. En retour, cela réduira les pics de performances que vos joueurs connaîtront.

J'ai hâte de travailler avec vous tous en 2020.
Ruben

Source: https://habr.com/ru/post/fr484710/


All Articles