Question

Je travaille sur un jeu pour la Xbox 360, en utilisant XNA. Sur la Xbox le garbage collector effectue assez mal par rapport à celle sur un PC, en gardant donc les déchets générés au minimum est indispensable pour un jeu en douceur l'exécution.

Je me souviens avoir lu une fois que l'appel d'un délégué crée des déchets, mais maintenant la vie de moi ne peut trouver aucune référence aux délégués de créer des déchets. Est-ce que je viens de faire ce ou sont délégués en désordre?

Si les délégués sont en désordre, des points bonus pour proposer une solution de contournement.

public delegate T GetValue<T>(T value, T[] args);

public static T Transaction<T>(GetValue<T> calculate, ref T value, params T[] args) where T : class
{
    T newValue = calculate(value, args);
    return foo(newValue);
}

Mon code ressemble vaguement que pour le moment, la seule solution que je peux penser à me débarrasser des délégués est de passer dans une classe qui hérite d'un IValueCalculator d'interface, puis je peux appeler la méthode sur cette interface, ce n'est pas vraiment très propre bien!

Était-ce utile?

La solution

Un délégué lui-même est un objet, donc si vous créez un délégué, peut-être une méthode anonyme, et donner ceci à une autre méthode pour exécuter et ne pas stocker le délégué à titre de référence, alors oui, que produira des déchets.

Par exemple, ceci:

collection.ForEach(delegate(T item)
{
    // do something with item
});

Dans ce cas, un nouvel objet délégué est créé, mais au-delà de l'appel à ForEach il n'est pas référencé, et donc admissibles à la collecte des ordures.

Cependant, appelant délégués fait en produire lui-même pas de déchets, pas plus que d'appeler toute autre méthode du même type serait. Par exemple, si vous appelez un délégué qui prend un paramètre Object, en passant une valeur Int32, cette valeur sera emballé, mais cela se passerait-il si vous avez appelé une méthode normale de la même façon.

Donc, en utilisant les délégués devrait être très bien, mais la création excessive des objets délégués sera un problème.


Modifier : Un bon article sur la gestion de la mémoire pour Xbox et XNA est ici: code de la gestion du rendement sur Xbox 360 pour XNA: partie 2 - GC et outils . Faites attention à cette citation:

  

Alors, comment une latence de contrôle GC? Comme netcf pour les appareils, la Xbox GC est non-générationnelle. Cela signifie que chaque collection est une collection complète sur le tas managé. Ainsi, nous constatons que la latence du GC est approximativement linéaire au nombre d'objets vivants ... puis ajouter le coût de compactage du tas à cela. Nos points de référence montrent que la différence entre les hiérarchies d'objets profonds contre les peu profondes est négligeable, il est donc la plupart du temps le nombre d'objets qui comptent. Les petits objets ont aussi tendance à être un peu moins cher à traiter que de grands objets.

Comme vous pouvez le voir, essayez d'éviter de créer beaucoup d'objets inutiles, et vous devriez sortent mieux.

Autres conseils

Dans l'environnement de bureau est effectivement libre des déchets . Il ce que vous voulez à vous soucier est de savoir combien non-ordures que vous produisez. Rappelez-vous comment le garbage collector fonctionne: il commence par des marques tous les objets connus, il efface la marque sur tous les objets vivants et compacts les objets vivants. L'étape coûteuse, il est « les objets vivants désélectionner ». La poubelle est de détruire pas cher; il est d'identifier les objets vivants qui est cher, et que le coût dépend du nombre d'objets vivants que vous avez (et la complexité de leur topologie de référence), et non sur le nombre d'objets morts que vous avez.

Cependant, sur XBOX et d'autres cadres compacts, le collecteur des ordures fonctionne assez fréquemment et fonctionne plus souvent lorsque de nouvelles allocations sont créées, alors oui, vous avez raison de vous soucier de créer des déchets aussi. Vous voulez à la fois garder le live petit (pour faire une collection pas cher) et ne pas faire de nouvelles allocations (parce que déclenche collections.)

Création un délégué n'alloue la mémoire, mais appeler un est rien de plus que d'appeler une méthode nommée Invoke sur une classe. Un délégué est pas beaucoup plus d'une classe avec une méthode nommée Invoke qui arrive à appeler immédiatement une autre méthode quand on l'appelle.

Peu importe, si vous avez un problème avec des performances mémoire, puis la bonne chose à faire est de sortir le profileur de mémoire et l'utiliser pour analyser votre programme. Coulée au hasard à propos de se demander si ceci ou cela arrive à allouer de la mémoire est comme essayer de désherber votre jardin avec des ciseaux à ongles; il faut beaucoup de temps et ne permet pas d'atteindre réellement vos objectifs. Utilisez un profileur pour analyser vos performances et de voir où sont les problèmes, puis les corriger.

Création de délégué génère des déchets, comme d'autres déjà noté.

Dans votre exemple, en utilisant l'argument de params génère probablement des déchets aussi bien.

Envisager de fournir sans utiliser mot-clé surcharges params.

C'est la raison pour laquelle avec un nombre différent surcharge d'arguments existent généralement dans les méthodes de la bibliothèque ainsi que celle utilisant le mot clé de params:

Voir String.Format Méthode (String, Object [])

Format Method (String, Object)
Format Method (String, Object[])
...
Format Method (String, Object, Object)
Format Method (String, Object, Object, Object)

Oui et non.

L'appel simple délégué n'alloue pas de choses sur tas, mais la création d'un délégué allouer 64 octets sur tas.

Afin d'éviter GC, vous pouvez créer au préalable le délégué.

Vérifions il:

using BenchmarkDotNet.Running;

namespace Test
{
    class Program
    {
        static void Main(string[] args)
        {
            var summary = BenchmarkRunner.Run<BenchmarkDelegate>();            
        }
    }
}

Indice de référence:

using BenchmarkDotNet.Attributes;

namespace Test
{
    [MemoryDiagnoser]
    public class BenchmarkDelegate
    {
        public delegate int GetInteger();

        GetInteger _delegateInstance;

        public BenchmarkDelegate()
        {
            _delegateInstance = WithoutDelegate;
        }

        [Benchmark]
        public int WithInstance() => RunDelegated(_delegateInstance);

        [Benchmark]
        public int WithDelegate() => RunDelegated(WithoutDelegate);

        public int RunDelegated(GetInteger del) => del();

        [Benchmark]
        public int WithoutDelegate() => 0;
    }
}

La sortie suivante, faites défiler à droite pour voir Numéroté mémoire / Op colonne:

DefaultJob : .NET Core 2.2.1 (CoreCLR 4.6.27207.03, CoreFX 4.6.27207.03), 64bit RyuJIT
|          Method |       Mean |     Error |    StdDev | Gen 0/1k Op | Gen 1/1k Op | Gen 2/1k Op | Allocated Memory/Op |
|---------------- |-----------:|----------:|----------:|------------:|------------:|------------:|--------------------:|
|    WithInstance |  7.5503 ns | 0.0751 ns | 0.0702 ns |           - |           - |           - |                   - |
|    WithDelegate | 35.4866 ns | 1.0094 ns | 1.2766 ns |      0.0203 |           - |           - |                64 B |
| WithoutDelegate |  0.0000 ns | 0.0000 ns | 0.0000 ns |           - |           - |

       - |                   - |
Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top