Peut à l'aide de lambda que les gestionnaires d'événements provoquer une fuite de mémoire?

StackOverflow https://stackoverflow.com/questions/16473

Question

Disons que nous avons la méthode suivante:

private MyObject foo = new MyObject();

// and later in the class

public void PotentialMemoryLeaker(){
  int firedCount = 0;
  foo.AnEvent += (o,e) => { firedCount++;Console.Write(firedCount);};
  foo.MethodThatFiresAnEvent();
}

Si la classe avec cette méthode est instancié et l' PotentialMemoryLeaker la méthode est appelée plusieurs fois, n'avons-nous une fuite de mémoire?

Est-il possible de décrocher que les lambda gestionnaire d'événement après nous avons fait appel MethodThatFiresAnEvent?

Était-ce utile?

La solution

Oui, l'enregistrer dans une variable et le décrocher.

DelegateType evt = (o, e) => { firedCount++; Console.Write(firedCount); };
foo.AnEvent += evt;
foo.MethodThatFiresAnEvent();
foo.AnEvent -= evt;

Et oui, si vous ne le faites pas, vous aurez fuite de mémoire, comme vous allez le raccordement d'un nouveau délégué objet à chaque fois.Vous remarquerez également que cela parce que chaque fois que vous appelez cette méthode, il va de vidage de la console, un nombre croissant de lignes (et pas seulement à un nombre croissant, mais, pour un appel à MethodThatFiresAnEvent il va dump n'importe quel nombre d'éléments, une fois pour chaque accroché méthode anonyme).

Autres conseils

Vous avez l'habitude vient de fuite de mémoire, vous obtiendrez également votre lambda appelée plusieurs fois.Chaque appel à "PotentialMemoryLeaker' va ajouter une autre copie du lambda à la liste des événements, et chaque copie sera appelé lors de la 'AnEvent' est déclenché.

Eh bien, vous pouvez prolonger ce qui a été fait ici pour faire délégués de plus sûr à utiliser (pas de fuites de mémoire)

Votre exemple qui vient d'être compilé en un compilateur nommé privé intérieur de la classe (avec le champ firedCount et un compilateur méthode nommée).Chaque appel à PotentialMemoryLeaker crée une nouvelle instance de la classe de fermeture à qui, où foo garde une référence par le biais d'un délégué à la méthode unique.

Si vous n'avez pas de référence de l'ensemble de l'objet qui possède PotentialMemoryLeaker, alors que tout sera nettoyée.Sinon, vous pouvez soit définir foo la valeur null ou vide foo liste de gestionnaire d'événements en écrivant ceci:

foreach (var handler in AnEvent.GetInvocationList()) AnEvent -= handler;

Bien sûr, vous auriez besoin d'accéder à la Monobjet la classe de membres privés.

Oui de la même manière que la normale des gestionnaires d'événements peuvent provoquer des fuites.Parce que le lambda est effectivement changé:

someobject.SomeEvent += () => ...;
someobject.SomeEvent += delegate () {
    ...
};

// unhook
Action del = () => ...;
someobject.SomeEvent += del;
someobject.SomeEvent -= del;

Donc, fondamentalement, il est juste à court de main pour quoi nous avons été à l'aide de 2.0 toutes ces années.

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