Pourquoi devrais-je toujours envisager de créer et d'utiliser des pools d'objets au lieu d'instancier le nouvel objet à la volée?

25

J'ai lu plusieurs fois ce modèle (du point de vue des meilleures pratiques):

Allocation de mémoire : au lieu d'instancier le nouvel objet à la volée, pensez toujours à créer et à utiliser des pools d'objets. Cela contribuera à réduire la fragmentation de la mémoire et à rendre le garbage collector moins efficace.

Cependant, je ne sais pas ce que cela signifie réellement. Comment puis-je l'implémenter?

Par exemple, je peux instancier un en GameObjectutilisant la Instantiateméthode Unity?

Instantiate(prefab, new Vector3(2.0F, 0, 0), Quaternion.identity);

Cette utilisation est-elle déconseillée? Que peut-il signifier d'autre?

Muhammad Faizan Khan
la source
Merci Hellium, je n'ai pas regardé la vidéo donnée (trop grande) mais le texte m'aide vraiment à comprendre "L'acte d'instanciation et de destruction est inefficace et peut ralentir vos projets"
Muhammad Faizan Khan
1
Notez que bien que ce conseil soit courant, ce n'est pas une exigence absolue pour chaque jeu. Surtout si vous créez un petit / court jeu de bureau, une soumission de jam ou un prototype, vous n'avez pas besoin de vous démener pour mettre en œuvre le pooling. Dans mes tests de trempage, Unity résiste même à une reproduction et à une destruction massives mieux que nous ne le croyons. ;) Mais pensez à la mise en commun si vous faites un long jeu où vous ne voulez pas que les ordures s'accumulent et provoquent un bégaiement lorsqu'elles sont collectées plus tard, ou si vous ciblez des plates-formes mobiles où tout impact sur les performances se fait sentir plus fortement.
DMGregory
Merci @DMGregory Vous avez raison. votre contribution est toujours précieuse. Nous ne devons pas nous soucier du regroupement d'objets dans les petits jeux car cela nécessitera un travail supplémentaire dans le codage.
Muhammad Faizan Khan,
1
Il s'agit d'un modèle très courant, mais assurez-vous de le tempérer avec la règle: "Profilez d'abord, puis optimisez." Il est facile d'optimiser les choses qui n'ont pas d'importance.
Cort Ammon - Reinstate Monica

Réponses:

41

Si vous prévoyez d'instancier de nombreuses instances du même préfabriqué, vous devez absolument penser à utiliser le pool d'objets. L'appel de la fonction Instantiate d'Unity est l'un des appels de méthode les plus taxables que vous puissiez faire.

Le regroupement d'objets consiste à instancier des préfabriqués avant de les utiliser. Ils sont désactivés immédiatement lors de l'instanciation et réactivés uniquement lorsqu'ils sont nécessaires. Bien que cela augmente l'utilisation de la mémoire, cela évite la surcharge du processeur de l'instanciation pendant le jeu.

Par exemple, je travaille actuellement sur un jeu d'enfer qui nécessite la génération de centaines de balles lors de l'exécution. J'ai d'abord essayé de faire le jeu sans regroupement d'objets mais cela a fini par être un désastre (moins de 2 fps). Maintenant, je rassemble 500 balles avant le début du jeu et le jeu est incroyablement rapide (200 fps).

Il existe des situations où le regroupement d'objets ne peut pas être utilisé. Par exemple, si vous avez un jeu où l'entrée du joueur dicte quel préfabriqué est généré, alors vous n'aurez pas d'autre choix que d'utiliser l'appel normal d'Instantiate. Le regroupement d'objets n'est possible que si vous savez à l'avance quels objets seront nécessaires.

Le didacticiel YouTube de Sebastian Lague est une excellente ressource pour en savoir plus sur le regroupement d'objets: https://youtu.be/LhqP3EghQ-Q

Kevin H.
la source
"L'acte d'instancier et de détruire est inefficace et peut ralentir vos projets". c'est la raison? Cela signifie donc que nous devons coder un peu plus (comme activer la désactivation, ou définir à nouveau la position de la balle pour que nous puissions tirer à nouveau)
Muhammad Faizan Khan
12
Il peut être utile de mentionner l'allocation et la collecte des ordures comme principaux contributeurs au coût des instanciations et destructions répétées. Générez suffisamment de déchets et, éventuellement, tout le jeu doit attendre que le ramasseur de déchets balaie tout. ;)
DMGregory
3
@corsiKa qui serait une optimisation de l'ère des années 80. Unity peut simplement désactiver les préfabriqués en question, ce qui fait que ses systèmes l'ignorent.
congusbongus
2
"Par exemple, si vous avez un jeu où l'entrée du joueur dicte quel préfabriqué est généré, alors vous n'aurez pas d'autre choix que d'utiliser l'appel normal d'Instantiate." - Pas vraiment. Vous pouvez facilement avoir plusieurs pools d'objets pour différents préfabriqués alloués aux tailles souhaitées au démarrage (ou au chargement de la scène). Ou, si l'on voulait le faire, un pool d'objets qui stocke plusieurs types de préfabriqués pourrait également fonctionner.
Ethan Bierlein
1
@DMGregory Dans un environnement de GC typique, la désallocation représente la majeure partie du coût; dans un environnement non GC typique, l'allocation représente l'essentiel du coût. La mise en commun d'objets fonctionne très bien pour les deux, ce ne sont en fait que les deux faces d'une même pièce pour la plupart. Dans le cas extrême, les anciens jeux étaient écrits avec tous les objets «alloués» dès le départ - très peu ou pas de mémoire / allocation de mémoire pendant le jeu. Vous n'avez pas vraiment utilisé quelque chose qui n'était pas "mis en commun" d'une manière ou d'une autre. Étant donné qu'Unity utilise beaucoup de "métadonnées" en temps réel, la mise en commun peut être très utile - même si elle peut également être plus difficile à mettre en œuvre.
Luaan