2011-05-06 2 views
14

Vorrei verificare che il codice che imposta un WeakReference non contenga accidentalmente un riferimento forte all'oggetto di riferimento. (Ecco an example di come è facile farlo accidentalmente.)Test/verifica di un debole riferimento

Questo sembra il modo migliore per verificare la presenza di forti riferimenti involontari?

TestObject testObj = new TestObject(); 
WeakReference wr = new WeakReference(testObj); 

// Verify that the WeakReference actually points to the intended object instance. 
Assert.Equals(wr.Target, testObject); 

// Force disposal of testObj; 
testObj = null; 
GC.Collect(); 
// If no strong references are left to the wr.Target, wr.IsAlive will return false. 
Assert.False(wr.IsAlive); 
+0

Non si può pretendere GC.Collect(), per forzare il GC per la raccolta dei rifiuti, è solo un suggerimento, quindi potrebbe non rimuovere l'oggetto. [Raccolta automatica della memoria in .Net] (http://msdn.microsoft.com/en-us/library/f144e03t.aspx) –

+0

Ti dispiacerebbe elaborare il motivo per cui GC.Collect() non può distruggere un oggetto idoneo per collezione? –

+0

Apparentemente impone in modalità predefinita. È solo quando è impostato in modalità ottimizzata che non lo è, non me ne sono reso conto. –

risposta

11

sono entrato in contatto con Microsoft su questo e ho imparato/ha confermato che:

  • GC.Collect() costringe una garbage collection blocco .
  • Quando si esegue GC.Collect(), non si ignorano misteriosamente oggetti idonei alla raccolta. Seguono regole prevedibili per determinare quali oggetti collezionare. Finché si opera con una comprensione di tali regole (ad esempio come vengono gestiti gli oggetti finalizzabili), è possibile forzare la distruzione di un oggetto particolare, sebbene la memoria utilizzata dall'oggetto distrutto possa o meno essere liberata.

Maggiori informazioni sul mio blog: Can .Net garbage collection be forced?

4

Ho fatto solo ieri. Ecco cosa ho dovuto aggiungere per assicurare la raccolta è accaduto prima del tuo ultimo affermare:

 GC.Collect(); 
     GC.WaitForPendingFinalizers(); 
     GC.WaitForFullGCComplete(); 
     GC.Collect(); 

Se dopo questo .IsAlive è ancora vero, è probabile che v'è ancora un punto di riferimento forte da qualche parte.

Incidentalmente: assicurarsi di NON controllare .IsAlive quando si accede al target WeakReference. Per evitare una condizione di competizione tra voi che controllate .IsAlive e .Target, fare questo:

var r = weakRef.Target AS Something; 
if (r != null) 
{ 
    ... do your thing 
} 
+0

Il codice non * assicura * che l'oggetto sia stato raccolto, non è possibile forzare il GC in questo modo. Puoi ancora usare 'IsAlive' se fai un doppio check, cioè controlla anche null dopo aver ottenuto il target. Questo può essere utile se vuoi che il controllo salti presto, senza dover fare il casting se è certo che non c'è niente da trasmettere. – Guffa

+3

GC.Collect() preforma una raccolta di blocchi: il metodo ritorna solo al termine della raccolta, pertanto la chiamata a GC.WaitForFullGCComplete() non dovrebbe essere necessaria. GC.WaitForFullGCComplete() è destinato all'uso in uno scenario diverso. –