IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

Framework .NET Discussion :

[GC] Savoir si une référence existe vers un objet


Sujet :

Framework .NET

  1. #1
    Expert éminent
    Avatar de smyley
    Profil pro
    Inscrit en
    Juin 2003
    Messages
    6 270
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juin 2003
    Messages : 6 270
    Points : 8 344
    Points
    8 344
    Par défaut [GC] Savoir si une référence existe vers un objet


    J'ai un "grave" problème
    La manière dont le GC dispose les objets est chaotique. Prenons un exemple. J'ai un objet A qui contient une référence vers un objet B. Cette dernière doit normalement est libérée lorsque A est finalisé (c'est le but, il s'agit d'un flux enfant, qui ne doit pas exister sans son parent).

    Cependant le GC passe par là, il vois que plus aucune référence n'existe sur A, dispose A se qui détruit B (par appel à B.Close) et boum, tout ceux qui utilisaient B se retrouve avec une référence invalide qui entraine inexorablement mon programme vers un crash fatal.

    Donc, comment savoir si un objet B est toujours référencé afin de ressusciter A et/ou quelles sont les meilleurs moyens de résoudre mon problème (qu'un objet enfant vive tant que son parent est envie, que le parent vive tant que l'enfant est envie, mais que le tout soit disposable si il n'y a plus aucune référence vers le parant ou l'enfant) ?

    d'avance

  2. #2
    Expert éminent sénior
    Avatar de Skyounet
    Homme Profil pro
    Software Engineer
    Inscrit en
    Mars 2005
    Messages
    6 380
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 37
    Localisation : Etats-Unis

    Informations professionnelles :
    Activité : Software Engineer
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Mars 2005
    Messages : 6 380
    Points : 13 380
    Points
    13 380
    Par défaut
    Je comprends pas très bien le problème.

    Si des objets référencent encore B, le GC ne va rien entreprendre il me semble, ce serait complètement idiot d'ailleurs.

    Code c# : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    static void Main(string[] args)
    {
        A a = new A();
        B b = new B();
     
        a.File = File.Open("test.txt", FileMode.Open);
     
        b.File = a.File;
     
        Console.WriteLine(a.File.CanRead == true ? "open" : "close");
     
        a = null;
        GC.Collect();
     
        Console.WriteLine(b.File.CanRead == true ? "open" : "close");
     
        Console.Read();
    }
     
    class A
    {
        public FileStream File { get; set; }
    }
     
    class B
    {
        public FileStream File { get; set; }
    }

    Affiche : open open ce qui est le résultat attendu.
    la méthode Close n'est pas appelée.

  3. #3
    Expert éminent
    Avatar de smyley
    Profil pro
    Inscrit en
    Juin 2003
    Messages
    6 270
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juin 2003
    Messages : 6 270
    Points : 8 344
    Points
    8 344
    Par défaut
    Code c# : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    class FinalizeChecker
            {
                bool finalized = false;
     
                public bool Finalized
                {
                    get { return finalized; }
                }
     
                ~FinalizeChecker()
                {
                    finalized = true;
                }
     
                public void FinalizeForcé()
                {
                    finalized = true;
                }
            }
     
            class A
            {
                FinalizeChecker myChecker = new FinalizeChecker();
     
                public FinalizeChecker MyChecker
                {
                    get { return myChecker; }
                }
     
                ~A()
                {
                    MyChecker.FinalizeForcé();
                }
            }
     
            private WeakReference CreateA()
            {
                A a = new A();
                return new WeakReference(a);
            }
     
            private FinalizeChecker CreateFinalizeChecker()
            {
                WeakReference myRef = CreateA();
     
                FinalizeChecker check = (myRef.Target as A).MyChecker;
                return check;
            }
     
            private void button1_Click(object sender, EventArgs e)
            {
                FinalizeChecker check = CreateFinalizeChecker();
     
                GC.Collect();
                GC.WaitForPendingFinalizers();
                GC.Collect();
                GC.WaitForPendingFinalizers();
     
                MessageBox.Show(check.Finalized.ToString());
             }

    La boite de message renvoi True, donc A a été détruit, entrainant le check dans sa tombe...
    Ce que je voudrais c'est pouvoir faire un code du genre
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
     
    ~A()
    {
      if(EstReferencéAilleursQueDansA(MyChecker))
      {
        résurection();
      }
      else
      {
        MyChecker.FinalizeForcé();
       }
    }
    ou alors, maintenir A en vie tant que quelqu'un d'autre que A détient une référence vers le check ...

  4. #4
    Rédacteur
    Avatar de SaumonAgile
    Homme Profil pro
    Team leader
    Inscrit en
    Avril 2007
    Messages
    4 028
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Moselle (Lorraine)

    Informations professionnelles :
    Activité : Team leader
    Secteur : Conseil

    Informations forums :
    Inscription : Avril 2007
    Messages : 4 028
    Points : 6 334
    Points
    6 334
    Par défaut
    J'ai du mal à comprendre ce que tu cherches à faire avec des WeakReferences. L'idée d'une wr, c'est qu'elle n'est pas comptabilisée dans la liste des references permettant ainsi à la variable d'être collectée.

    Le truc dans ton createjenesaisplusquoi, c'est que tu ne testes pas si elle est "vivante" avec IsAlive, alors c'est normal que ça pète si elle a déjà été collectée.

  5. #5
    Expert éminent
    Avatar de smyley
    Profil pro
    Inscrit en
    Juin 2003
    Messages
    6 270
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juin 2003
    Messages : 6 270
    Points : 8 344
    Points
    8 344
    Par défaut
    La WeakReference porte sur A, d'ailleurs, elle n'était peut être pas nécéssaire dans mon exemple.
    En fait le scénario est le suivant :
    J'ai une classe d'accès aux données qui charge plusieurs flux et la gère elle même. Cependant, pour ne pas en avoir une infinité chaque objet de gestion des données est indépendant des autres de sorte que si quelqu'un demande la donnée et qu'elle est déjà chargée, une référence vers cet objet déjà chargé est renvoyée, sinon, un nouvel objet est crée avec les flux qui vont avec.
    Cette objet est chargé de la gestion des flux donc, et s'occupe de charger/enregistrer les données quand il le faut. Celà peut être sur demande explicite de l'utilisateur (Commit) ou automatiquement si plus aucune référence vers l'objet n'est utilisée (donc Finalize->Commit du flux et déchargement de l'entrée du cache).
    Cependant il arrive que certaines classes (en particulier celles dont je n'ai pas accès, classes du Framework) utilisent un flux et le balade un peut partout. Cependant il n'y a qu'une référence vers le flux mais pas vers l'objet d'accès aux données donc le GC passe et ne vois aucune référence donc appelle Finalize qui libère les flux qui se trouvent en réalité être en cours d'utilisation par d'autres objets et ils sont fermés ce qui provoque des ObjectDisposedException un peut n'importe où.

    Ce que je voudrais c'est informer le GC que tant qu'une référence existe vers le flux de ne pas collecter l'objet d'accès mais de préférence sans changer le code des classes qui gèrent les flux mais plus via l'objet d'accès aux données afin d'annuler la finalization si le flux est toujours utilisé (avec ReRegisterForFinalize)...

    Réalisable ?

  6. #6
    Expert éminent
    Avatar de smyley
    Profil pro
    Inscrit en
    Juin 2003
    Messages
    6 270
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juin 2003
    Messages : 6 270
    Points : 8 344
    Points
    8 344
    Par défaut
    Bon ben j'ai pris un chemin détourné et il semblerai que j'obtienne le résultat voulu ...
    Code c# : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    class A
            {
                class RefCountedFinalizeChecker : FinalizeChecker
                {
                    FinalizeChecker target;
     
                    public RefCountedFinalizeChecker(FinalizeChecker target)
                    {
                        this.target = target;
     
                        target.RefCount++;
                    }
     
                    ~RefCountedFinalizeChecker()
                    {
                        target.RefCount--;
                    }
                }
     
                FinalizeChecker myChecker = new FinalizeChecker();
     
                public FinalizeChecker MyChecker
                {
                    get { return new RefCountedFinalizeChecker(myChecker); }
                }
     
                ~A()
                {
                    if (myChecker.RefCount > 0)
                    {
                        Trace.WriteLine("Resurection de this, car FinalizeChecker est toujours utilisé");
                        GC.ReRegisterForFinalize(this);
                    }
                    else
                    {
                        myChecker.FinalizeForcé();
                        Trace.WriteLine("Check Killed");
                    }
                }
            }

+ Répondre à la discussion
Cette discussion est résolue.

Discussions similaires

  1. Comment savoir si une URL existe
    Par funzynator dans le forum VB 6 et antérieur
    Réponses: 14
    Dernier message: 07/11/2005, 20h56
  2. [VBA-E]Savoir si une sheets existe
    Par wind_vinch dans le forum Macros et VBA Excel
    Réponses: 5
    Dernier message: 13/10/2005, 14h31
  3. comment savoir si une table existe dans la base?
    Par isa21493 dans le forum ASP
    Réponses: 6
    Dernier message: 01/09/2005, 17h09
  4. Savoir si une table existe
    Par Sydaze dans le forum Bases de données
    Réponses: 4
    Dernier message: 07/06/2005, 11h22
  5. [URL] Comment savoir si une URL existe?
    Par jse dans le forum Entrée/Sortie
    Réponses: 5
    Dernier message: 07/10/2004, 15h33

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo