2012-12-17 12 views
5

Ecco una domanda accademica sulla finalizzazione e raccolta degli oggetti in C# /. NET. La lettura in background è la sezione 3.9 delle specifiche del linguaggio C#, Gestione automatica della memoria.Comportamento di WeakReference quando l'oggetto viene finalizzato ma non ancora eliminato. Raccolta dati

Quando non ci sono riferimenti espliciti a un oggetto, esso può diventare garbage collector. Diventa "idoneo per la distruzione". Ad un certo punto nel futuro (ad es. Se forzate la garbage collection), verrà eseguito il distruttore dell'oggetto.

Nel distruttore, se si salva un riferimento all'oggetto, l'oggetto sarà finalizzato, ma non sarà idoneo per la raccolta. Ciò può portare a un oggetto che si trova in uno stato in cui è stato finalizzato, ma non raccolto. Il paragrafo 3.9 delle specifiche ha un esempio di questo.

A questo punto, l'oggetto è ancora vivo, poiché non è ancora stato raccolto. Tuttavia, una WeakReference riferita all'oggetto riporta un valore IsAlive di false, che indica che l'oggetto è stato raccolto.

La domanda principale è questa: qual è la proprietà IsAlive che segnala realmente? Sappiamo che non possiamo fidarci di un valore true per questa proprietà, perché il valore può diventare falso poco dopo averlo letto. Ma un valore di falso è affidabile e intende indicare (secondo la documentazione) che l'oggetto è stato garbage collection. Allora, qual è la proprietà IsAlive che ci dice in questo caso? Non strettamente se l'oggetto è stato garbage collection, dal momento che crediamo che l'oggetto sia in uno stato finalizzato ma non in quello raccolto.

Ecco un esempio per mostrare il comportamento.

public class Dog 
    { 
     public static Dog KeepDogRef; 



    public string Name { get; set; } 

    public Dog(string name) 
    { 
     Name = name; 
    } 

    ~Dog() 
    { 
     Console.WriteLine("Dog destructor for " + Name + " called"); 
     Dog.KeepDogRef = this; 
    } 

    public void Bark() 
    { 
     Console.WriteLine(Name + " : Woof"); 
    } 
} 

E codice per programma principale. Se esegui il codice, vedrai che l'originale WeakReference riporta IsAlive come falso, anche dopo la ricostituzione dell'oggetto.

static void Main() 
    { 
     Dog dog = new Dog("Bowser"); 

     WeakReference dogRef = new WeakReference(dog); 

     // Unref Bowser, now eligible for destruction 
     dog = null; 
     GC.Collect(); 
     GC.WaitForPendingFinalizers(); 

     // Bowser no longer alive 
     Console.WriteLine(string.Format("Object still alive: {0}", dogRef.IsAlive)); 

     // Bowser alive again 
     Dog newRef = Dog.KeepDogRef; 
     newRef.Bark(); 
    } 
} 

risposta

7

Se leggete tutta la documentazione per WeakReference, è chiaro che non v'è più di un tipo di riferimento debole disponibili. Il valore predefinito è di produrre un riferimento debole short. Ma è anche possibile creare long riferimenti deboli che specificatamente rappresentano scenari di resurrezione.

Dalla documentazione per TrackResurrection:

Ottiene l'indicazione se l'oggetto a cui fa riferimento l'oggetto WeakReference corrente viene monitorato dopo che è stato finalizzato.

Se vero, il riferimento debole è un riferimento debole lungo e vero è stato specificato per il parametro trackResurrection nel costruttore WeakReference.

Quindi direi che è necessario comprendere questa parte di riferimenti deboli prima di interpretare la proprietà IsAlive.

+0

Questa sembra essere la risposta. Per un riferimento debole e breve, il Target del riferimento debole diventa null non appena viene chiamato il finalizzatore. Per un riferimento debole e lungo, diventa nullo solo quando l'oggetto viene effettivamente raccolto. La documentazione MSDN è un po 'fangosa su questo. La documentazione di short vs long è chiara, ma la documentazione della proprietà IsAlive non è del tutto accurata, in quanto indica che IsAlive diventa falso quando viene raccolto l'oggetto.Tecnicamente, per brevi riferimenti deboli, diventa falso solo quando l'oggetto è stato finalizzato, ma prima che sia effettivamente raccolto. –

+3

@SeanSexton: leggera correzione: il riferimento debole viene invalidato non appena il sistema rileva che l'oggetto sarebbe idoneo per la raccolta ma per l'esistenza del finalizzatore e lo aggiunge a un elenco di oggetti i cui metodi di finalizzazione devono essere eseguiti all'inizio opportunità. Di solito il finalizzatore verrà eseguito molto presto, ma potrebbe essere arbitrariamente ritardato. Qualsiasi breve 'WeakReference' che bersaglia l'oggetto sarebbe invalidato non appena l'oggetto è stato trovato abbandonato, comunque, indipendentemente da quando il finalizzatore viene effettivamente eseguito. – supercat

+0

BTW, una stranezza piuttosto sgradevole, che è particolarmente fastidiosa con lunghi riferimenti deboli, è che un riferimento debole che diventa idoneo per la finalizzazione sarà invalidato, * anche se i riferimenti sia al 'WeakReference' che al suo obiettivo esistono ancora *. Per questo motivo, il codice che vuole usare un riferimento lungo e debole per garantire che un oggetto sia ben e veramente morto potrebbe aver bisogno di creare un riferimento statico da qualche parte al 'WeakReference' stesso, e avere qualche altro oggetto determinare periodicamente se il' WeakReference' sta ancora facendo qualcosa di utile e uccide il riferimento statico una volta che non lo è. – supercat

Problemi correlati