Partage
  • Partager sur Facebook
  • Partager sur Twitter

[C#] Éviter de garder des références inutilisées en mémoire

Dispose(), définition à null, ...

Sujet résolu
Anonyme
    30 mars 2012 à 18:24:30

    Bonsoir. (ou bonjour, après tout, il fait beau...)

    J'essaie de minimiser l'empreinte mémoire de mon client IRC. Le plus gros point est évidemment le fait d'éviter d'utiliser de la mémoire pour rien ; idéalement, si je me connectes à un réseau à un instant T1 puis que je m'y déconnecte à un instant T2, la différence de mémoire utilisée entre T2 et T1 devrait être pratiquement nulle.

    J'ai de la peine à comprendre comment on évite de garder des références à un objet que l'on utilise plus. A ce que j'ai compris, si un objet possède directement ou indirectement des ressources non managées (FileStream, NetworkStream, ...) il faut lui faire implémenter IDisposable en appelant Dispose() sur tous les objets possédant des ressources non managées qu'il référence. Ça, ça va.
    Mais qu'en est-il des références elle-mêmes ? Faut-il absolument se désabonner de tous les event handlers auquel on s'est abonné ? Faut-il définir tous ses évènements à null pour éviter que d'autres objets soient gardés en mémoire à cause d'eux ? Faut-il définir tous ses membres de types références à null ?

    Premier exemple : j'ai une collection d'objets assez complexes. J'en détruis un. Comment être sûr qu'il sera marqué comme "à collecter" par le GC, ainsi que toutes les classes qu'il référence ?

    Deuxième exemple, j'ai une classe A (pour simplifier) et une classe B. La classe A possède une propriété de type B, et la classe B un membre de type A. L'instance de A référençant B est celle référencée par B (une sorte de référence circulaire). Faut-il définir B.A à null puis A.B à null dans A.Dispose() ?

    Troisième exemple : j'ai une classe C qui possède une propriété de type D, et qui s'abonne à une vingtaine de ses évènements. Faut-il se désabonner de tous les évènements de D dans le C.Dispose() ? Ou bien appeler D.Dispose() est suffisant ? Ou faut-il définir tous les évènements à null dans D.Dispose() ?

    Merci d'avance ^^
    • Partager sur Facebook
    • Partager sur Twitter
      30 mars 2012 à 19:58:18

      Je ne répond surement pas au sujet...

      Juste pour dire que en ce qui concerne les références vagues (les abonnements aux events par exemple), ça ne coute rien d'appliquer les méthodes C++ ("tout ce qui est fait doit être défait quand on ne s'en sert plus" => Désabonnement des events quand c'est possible, appels de méthodes de finalisation quand c'est nécessaire...). Au mieux, ça t'évitera des bugs bizarre (il peut arriver qu'en pensant s'abonner sur l'event d'un nouvel objet, on s'abonne à un objet déjà existant...Du coup, le code de l'event s'exécute plusieurs fois...) et au pire, ça te fera perdre une centaine de cycle d'horloge pour faire le nécessaire ^^ (sur des CPU à 2GHz, la perte reste assez minime).

      Peut-être bon à savoir : Quand tu fais un système maison traitant des objets et que tu ne veux pas trop avoir à te soucier de ça, tu peux utiliser des WeakReference. C'est une classe qui, comme son nom l'indique, garde une référence faible vers un objet. Cependant, il te faudra bien sûr vérifier avant usage que ta référence est encore en vie ^^ .
      • Partager sur Facebook
      • Partager sur Twitter
      Anonyme
        31 mars 2012 à 9:32:27

        Les WeakReference sont intéressantes, je vais voir ce que je peux faire avec ça...merci.

        [EDIT] Y a-t-il un moyen facile d'utiliser une WeakReference comme DataContext, sans devoir changer tous les Bindings ou définir une propriété dans chaque View ?
        • Partager sur Facebook
        • Partager sur Twitter
        Anonyme
          1 avril 2012 à 9:47:45

          J'ai plus ou moins résolu mes problèmes....quelques conclusions, pour ceux que ça intéresse :
          • Définir les membres à null ne sert pas à grand-chose
          • Dans Dispose(), il faut se désabonner de tous les évènements produits par des objets qui vivront plus longtemps (p.ex. Application.Exit) pour ne pas être maintenu en vie par ces objets
          • L'équivalent du Dispose() pour les Controls WPF est l'évènement Unloaded
          • Dans les cas où il est impossible de savoir quand un objet se fera enlever de l'arbre logique (p.ex. dérivé de CollectionViewSource), il faut utiliser les WeakEvents en implémentant IWeakEventListener et en créant son propre WeakEventManager pour chaque évènement.
            Il y a deux (ou plus ?) WeakEventManagers déjà existants et bien utiles : PropertyChangedEventManager et CollectionChangedEventManager pour INotifyProperty/CollectionChanged.
          • Ne surtout pas binder sur des objets n'implémentant pas INotifyPropertyChanged, WPF utilise la réflexion pour écouter les changements et crée des références fortes.
          • Partager sur Facebook
          • Partager sur Twitter

          [C#] Éviter de garder des références inutilisées en mémoire

          × Après avoir cliqué sur "Répondre" vous serez invité à vous connecter pour que votre message soit publié.
          × Attention, ce sujet est très ancien. Le déterrer n'est pas forcément approprié. Nous te conseillons de créer un nouveau sujet pour poser ta question.
          • Editeur
          • Markdown