56 votes

Fuite de mémoire en C #

Est-il jamais possible dans un système géré de perdre de la mémoire lorsque vous vous assurez que toutes les poignées, les éléments qui implémentent IDispose sont éliminés?

Y a-t-il des cas où certaines variables sont omises?

64voto

Reed Copsey Points 315315

Les Gestionnaires d'événements sont une source courante de la non-évidence des fuites de mémoire. Si vous vous abonnez à un événement sur l'objet1 d'objet2, puis de faire de l'objet2.Dispose() et faire semblant qu'elle n'existe pas (et abandonner toutes les références à partir de votre code), il y a une référence implicite dans l'objet1 de l'événement qui permettra d'éviter objet2 d'être nettoyée.

MyType object2 = new MyType();

// ...
object1.SomeEvent += object2.myEventHandler;
// ...

// Should call this
// object1.SomeEvent -= object2.myEventHandler;

object2.Dispose();

C'est un cas courant de fuite - oublier de se désabonner facilement à partir d'événements. Bien sûr, si objet1 obtient recueillies, objet2 obtiendrez recueillies aussi bien, mais pas jusqu'alors.

41voto

Michael Meadows Points 15277

Je ne pense pas que les fuites de mémoire de type C ++ soient possibles. Le ramasse-miettes devrait en tenir compte. Il est possible de créer un objet statique qui agrège les références même si les objets ne sont plus jamais utilisés. Quelque chose comme ça:

 public static class SomethingFactory
{
    private static List<Something> listOfSomethings = new List<Something>();

    public static Something CreateSomething()
    {
        var something = new Something();
        listOfSomethings.Add(something);
        return something;
    }
}
 

C'est un exemple évidemment stupide, mais ce serait l'équivalent d'une fuite de mémoire d'exécution gérée.

27voto

Robert Rossney Points 43767

Comme d'autres l'ont souligné, tant qu'il n'y a pas un bug dans le gestionnaire de mémoire, les classes qui n'utilisent pas les ressources non managées ne sera pas une fuite de mémoire.

Ce que vous voyez dans .NET n'est pas de fuites de mémoire, mais des objets qui ne sont disposées. Un objet n'obtiendrez pas disposé aussi longtemps que le garbage collector peut trouver sur l'objet graphique. Donc, si tout objet vivant n'importe où est une référence à l'objet, il ne sera pas éliminé.

L'enregistrement d'un événement est un bon moyen pour ce faire. Si un objet s'inscrit à un événement, quel qu'il inscrit avec a une référence à elle, et même si vous éliminez toute autre référence à l'objet, jusqu'à ce qu'il annule l'inscription (ou de l'objet de l'enregistrement auprès devient inaccessible), il va rester en vie.

Donc, vous avez à regarder dehors pour les objets qui s'inscrivent pour les événements statiques sans votre connaissance. Une fonctionnalité utile de l' ToolStrip, par exemple, est que si vous changez de thème d'affichage, il va automatiquement afficher de nouveau dans le nouveau thème. Il accomplit cette fonctionnalité utile en vous inscrivant à la statique SystemEvents.UserPreferenceChanged événement. Lorsque vous changez votre thème Windows, l'événement est soulevé, et tous les de la ToolStrip objets qui sont à l'écoute de l'événement notifié qu'il y a un nouveau thème.

Ok, supposons que vous décidez de jeter un ToolStrip sur votre formulaire:

private void DiscardMyToolstrip()
{
    Controls.Remove("MyToolStrip");
}

Vous avez maintenant une ToolStrip qui ne mourra jamais. Même si elle n'est pas sur votre formulaire de plus, chaque fois que l'utilisateur modifie les thèmes de Windows seront consciencieusement dire le contraire inexistante) ToolStrip environ. Chaque fois que le garbage collector s'exécute, il pense que "je ne peux pas jeter cet objet au loin, l' UserPreferenceChanged événement est de les utiliser."

Ce n'est pas une fuite de mémoire. Mais il pourrait aussi bien être.

Des choses comme cela fait un profileur de mémoire inestimable. Exécuter un profileur de mémoire, et que vous allez dire "c'est étrange, il semble y avoir dix mille ToolStrip objets sur le tas, même si il n'y a qu'un sur mon formulaire. Comment est-ce arrivé?"

Oh, et au cas où vous vous demandez pourquoi certaines personnes pensent que les setters de propriété sont mal: pour obtenir un ToolStrip de se désinscrire de la UserPreferenceChanged événement, définir son Visible de la propriété d' false.

20voto

Christian Klauser Points 2611

Les délégués peuvent entraîner des fuites de mémoire non intuitives.

Chaque fois que vous créez un délégué à partir d'une méthode d'instance, une référence à cette instance est stockée "dans" ce délégué.

En outre, si vous combinez plusieurs délégués dans un délégué de multidiffusion, vous disposez d'un gros blob de références à de nombreux objets qui ne peuvent pas être récupérés tant que ce délégué de multidiffusion est utilisé quelque part.

17voto

Zach Johnson Points 12062

Si vous développez une application WinForms, une "fuite" subtile est la propriété Control.AllowDrop (utilisée pour activer le glisser-déposer). Si AllowDrop est défini sur "true", le CLR conservera toujours votre contrôle malgré un System.Windows.Forms.DropTarget . Pour résoudre ce problème, assurez-vous que votre propriété Control 's AllowDrop est définie sur false lorsque vous n'en avez plus besoin et le CLR se chargera du reste.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X