Ho una lezione che si tiene a un delegato, per valutare pigramente qualcosa in seguito.GC di delegati, cosa mi manca? (il mio delegato non viene ritirato)
Dopo averlo valutato, chiamando il delegato, ho cancellato il riferimento al delegato, sperando che fosse idoneo per la raccolta. Dopo tutto, potrebbe trattenere un mondo di variabili locali se è stato costruito come metodo anonimo.
Ho provato a creare un test unitario per verificarlo, ma non sembra funzionare come pianificato, invece sembra che sia le mie ipotesi su WeakReference
(che ho usato per scopi di test qui), o alcune altro presupposto, non regge l'acqua.
Date un'occhiata a questo codice, che è possibile eseguire in LINQPad
void Main()
{
WeakReference wr;
Lazy<int> l;
CreateTestData(out wr, out l);
wr.IsAlive.Dump(); // should be alive here
GC.Collect();
GC.WaitForPendingFinalizers();
GC.Collect();
wr.IsAlive.Dump(); // and alive here as well
l.Value.Dump(); // but now we clear the reference
GC.Collect(); // so one of these should collect it
GC.WaitForPendingFinalizers();
GC.Collect();
wr.IsAlive.Dump(); // and then it should be gone here
GC.KeepAlive(l);
}
void CreateTestData(out WeakReference wr, out Lazy<int> l)
{
Func<int> f =() => 10;
wr = new WeakReference(f);
l = new Lazy<int>(f);
}
public class Lazy<T>
{
private Func<T> _GetValue;
private T _Value;
public Lazy(Func<T> getValue)
{
_GetValue = getValue;
}
public T Value
{
get
{
if (_GetValue != null)
{
_Value = _GetValue();
_GetValue = null;
}
return _Value;
}
}
}
mi è stato presupposto che:
- Indipendentemente build di debug, debugger, da quando ho creato il delegato in un metodo separato, dal quale ritorno, non ci dovrebbe essere nulla che regge al delegato, ad eccezione degli oggetti
WeakReference
eLazy<T>
- Se chiedo il
Lazy<T>
oggetto abbandoni il proprio riferimento al delegato, che ridurrebbe i riferimenti solo quella cheWeakReference
è partecipazione - E poi forzare una garbage collection completa, supponendo che se l'unico sinistro riferimento è quello in
WeakReference
- Poi il delegato sarebbero raccolti, e la mia
WeakReference
indicherebbero che l'oggetto non è più vivo
l'uscita del codice è stato in tal modo dovrebbe essere (con i commenti):
true // not gc'ed after construction
true // not gc'ed after full GC, still beind held by Lazy<T>
10 // value from calling delegate
false // but is now gc'ed, Lazy<T> no longer has a reference to it
Ma invece l'output è:
true
true
10
true
Qualcuno può far luce su ciò che mi manca qui?
Ok, questo ha senso. Ho cambiato il delegato in modo che usasse una variabile locale per calcolarne i risultati, e questo è stato effettivamente raccolto. –
Domanda laterale: presumo che il compilatore non sia abbastanza intelligente da notare che più delegati, dello stesso tipo, che restituiscono lo stesso valore costante, possono essere creati una volta e riutilizzati ovunque? –
Fondamentalmente, il mio obiettivo era di fare un test che verificasse che il riferimento al delegato venisse abbandonato al momento giusto, per rendere possibile la garbage collection dove consentito, non necessariamente quel particolare delegato è stato raccolto.La modifica del delegato ha appena risolto il problema e i test ora vengono eseguiti come previsto. –