2012-06-27 9 views
7

Supponiamo che tu abbia una classe con una proprietà evento. Se istanziate questa classe in un contesto locale, senza riferimenti esterni, l'assegnazione di un'espressione lambda all'evento impedisce che l'istanza venga trasformata in garbage collection?I lambda assegnati a un evento impediscono la garbage collection dell'oggetto proprietario?

+1

Dovrebbe essere idoneo per GC. Non ne sono abbastanza sicuro per renderlo una risposta. –

+0

Non vedo perché questo si comporti diversamente dall'abbonare qualsiasi altra funzione (lambda o altro) a un evento. Quindi sono d'accordo con Tim. –

+0

possibile duplicato di [Garbage Collection quando si utilizzano delegati anonimi per la gestione degli eventi] (http://stackoverflow.com/questions/371109/garbage-collection-when-using-anonymous-delegates-for-event-handling) –

risposta

5

No, o verrà liberato, così come la funzione lambda. Non ci sono riferimenti a o da nessun'altra parte, quindi non c'è motivo per cui non dovrebbe essere liberato.

1

Quando il runtime lascia quel blocco di codice, non ci sono più riferimenti all'oggetto, quindi viene raccolto del garbage.

+0

Come fai a sapere che non ci sono più riferimenti allo storage locale? –

+0

Non importa se ci sono riferimenti a qualcosa. In effetti, lambda è probabilmente un oggetto con allocazione heap con un riferimento a tale oggetto, quindi la tua richiesta è falsa. Ciò che conta per il GC è se un oggetto è * raggiungibile *. – delnan

0

Dipende da cosa intendi esattamente per "contesto locale". Confronto:

static void highMem() 
{ 
    var r = new Random(); 
    var o = new MyClass(); 
    o.MyClassEvent += a => { }; 
} 
static void Main(string[] args) 
{ 
    highMem(); 
    GC.Collect(); //yes, it was collected 
} 

A:

static void Main(string[] args) 
{ 
    var r = new Random(); 
    { 
     var o = new MyClass(); 
     o.MyClassEvent += a => { }; 
    } 
    GC.Collect(); //no, it wasn't collected 
} 

Nel mio ambiente (Debug, VS 2010, Win7 x64), il primo era ammissibile per GC e la seconda non era (come controllato da avendo MyClass occupa 200MB di memoria e controllandolo in Task Manager), anche se era fuori portata. Suppongo che questo sia dovuto al fatto che il compilatore dichiara tutte le variabili locali all'inizio di un metodo, quindi al CLR, o non è fuori portata, anche se non è possibile utilizzarlo nel codice C#.

+1

'o' è fuori portata, ma lo scope ha poco a che fare con la garbage collection, i riferimenti live sono. Se viene utilizzato lo spazio di stack di un riferimento mentre un riferimento è ancora in ambito, può essere raccolto. Può anche essere raccolto prima che le operazioni su di esso siano finite, in alcuni casi. –

2

Risposta breve, no, o verrà liberata. Non preoccuparti per questo risposta

Leggermente più lungo:

il codice fa più o meno il seguente:

  1. creare qualche storage locale su quel thread per un riferimento ai nuovi MyClass (o).
  2. Crea il nuovo MyClass
  3. Memorizza un riferimento alla nuova MyClass a o.
  4. Creare un nuovo delegato dalla lambda.
  5. Assegnare il delegato all'evento (o ora ha un riferimento al delegato).

In qualsiasi momento durante questo, il GC può interrompere i thread e quindi esaminare quali oggetti sono o non sono radicati. I root sono oggetti statici o nella memoria locale di un thread (con cui intendo le variabili locali nell'esecuzione di un dato thread, implementate da uno stack, piuttosto che "Thread-Local Storage" che è essenzialmente una forma di staticità). Gli oggetti radicati sono radici, oggetti a cui fanno riferimento, oggetti a cui fanno riferimento e così via. Gli oggetti radicati non verranno raccolti, il resto sarà (salvo alcune cose extra da fare con i finalizzatori che ignoreremo per ora).

In nessun punto fino a questo momento dopo la creazione dell'oggetto MyClass non è stato eseguito il root dalla memoria locale del thread.

In nessun momento, fino a quando l'oggetto delegato non è stato creato, non è stato radicato dall'archivio locale del thread o dal MyClass che ha un riferimento ad esso.

Ora, cosa succede dopo?

Dipende. Il lambda non manterrà vivo il MyClass (il MyClass lo mantiene in vita, ma quando va in scena MyClass, lo fa anche il lambda). Questo non è abbastanza per rispondere "Will 'o' essere eleggibile per la raccolta dei rifiuti qui?" anche se.

void Meth0() 
{ 
    var o = new MyClass(); 
    o.MyClassEvent += (args) => {}; 
}//o is likely eligible for collection, though it doesn't have to be. 

void Meth1() 
{ 
    int i = 0; 
    { 
    var o = new MyClass(); 
    o.MyClassEvent += (args) => {}; 
    }//o is likely not eligible for collection, though it could be. 
    while(i > 100000000);//just wasting time 
} 

void Meth2() 
{ 
    { 
    var o = new MyClass(); 
    o.MyClassEvent += (args) => {}; 
    int i = 0;//o is likely eligible for collection, though it doesn't have to be. 
    while(i > 100000000);//just wasting time 
    } 
} 

void Meth3() 
{ 
    { 
    var o = new MyClass(); 
    o.MyClassEvent += (args) => {}; 
    var x0 = new MyClass();//o is even more likely eligible for collection, though it doesn't have to be. 
    var x1 = new MyClass();//o is even more likely eligible for collection, though it doesn't have to be. 
    var x2 = new MyClass();//o is even more likely eligible for collection, though it doesn't have to be. 
    var x3 = new MyClass();//o is even more likely eligible for collection, though it doesn't have to be. 
    var x4 = new MyClass();//o is even more likely eligible for collection, though it doesn't have to be. 
    var x5 = new MyClass();//o is even more likely eligible for collection, though it doesn't have to be. 
    var x6 = new MyClass();//o is even more likely eligible for collection, though it doesn't have to be. 
    var x7 = new MyClass();//o is even more likely eligible for collection, though it doesn't have to be. 
    var x8 = new MyClass();//o is even more likely eligible for collection, though it doesn't have to be. 
    var x9 = new MyClass();//o is even more likely eligible for collection, though it doesn't have to be. 
    var x10 = new MyClass();//o is even more likely eligible for collection, though it doesn't have to be. 
    var x11 = new MyClass();//o is even more likely eligible for collection, though it doesn't have to be. 
    int i = 0; 
    while(i > 100000000);//just wasting time 
    } 
} 

Meth0 è apparentemente il più semplice, ma in realtà non lo è, quindi torneremo ad esso.

Nel Meth1, l'implementazione è probabile di andarcene storage locale come lo è, in quanto non è più necessaria, così mentre o non è nel campo di applicazione, l'attuazione sarà ancora avere quel memoria locale in uso.

Nel meth2, l'attuazione potrebbe utilizzare la stessa memoria locale che stava usando per o per i quindi, anche se è ancora nella portata, sarebbe idoneo a raccogliere ("di portata", il programmatore potrebbe scegliere di fare qualcosa con esso, ma lui o lei no e il codice compilato non ha bisogno di un tale concetto).

È più probabile che Meth3 riutilizzi lo spazio di archiviazione, poiché gli usi extra temporali di tale implementazione rendono più sensata l'implementazione rispetto all'impostazione di tutto lo spazio di archiviazione.

Nessuna di queste cose ha questo. Meth2 e Meth3 potrebbero entrambi mettere da parte tutta la memoria necessaria per il metodo all'inizio. Meth1 potrebbe riutilizzare lo storage perché non fa alcuna differenza per riordinare i e o assegnato.

Meth0 è più complicato perché potrebbe dipendere dal metodo di chiamata successivo all'archiviazione locale, piuttosto che da una ripulitura al momento (entrambe sono implementazioni legittime). IIRC c'è sempre una ripulitura dell'attuale implementazione, ma non ne sono sicuro e non importa comunque.

In generale, l'ambito non è la cosa rilevante, ma se il compilatore e in seguito il JITter possono e fanno uso della memoria locale relativa a un oggetto. È persino possibile pulire un oggetto prima che vengano invocati metodi e proprietà (se tali metodi e proprietà non fanno uso di this o di uno dei campi dell'oggetto, perché funzionerà perfettamente se l'oggetto è stato cancellato!).