11

Vedi anche queste risorse correlati:Un compilatore C# conforme può ottimizzare una variabile locale (ma non utilizzata) se è l'unico riferimento forte a un oggetto?


In altre parole:

Può un oggetto a cui fa riferimento una variabile locale essere recuperato prima della variabile esula dall'ambito (es. perché la variabile è assegnato, ma poi non riutilizzato), o è che oggetto garantita ammissibili per garbage collection finché la variabile passa nell'ambito?

Mi spiego:


void Case_1() 
{ 
    var weakRef = new WeakReference(new object()); 

    GC.Collect(); // <-- doesn't have to be an explicit call; just assume that 
        //  garbage collection would occur at this point. 

    if (weakRef.IsAlive) ... 
} 

In questo esempio di codice, io ovviamente devo pianificare per la possibilità che la new'ed object venga recuperato dalla garbage collector; quindi la dichiarazione if.

(Si noti che sto usando weakRef per il solo scopo di verificare se il new'ed object è ancora in giro.)


void Case_2() 
{ 
    var unusedLocalVar = new object(); 
    var weakRef = new WeakReference(unusedLocalVar); 

    GC.Collect(); // <-- doesn't have to be an explicit call; just assume that 
        //  garbage collection would occur at this point. 

    Debug.Assert(weakRef.IsAlive); 
} 

Il cambiamento principale in questo esempio di codice da quella precedente è che il new'ed object è fortemente referenziato da una variabile locale (unusedLocalVar). Tuttavia, questa variabile non viene mai più utilizzata dopo la creazione del riferimento debole (weakRef).


Domanda: è un conforme compilatore C# permesso di ottimizzare le prime due righe di Case_2 in quelle di Case_1 se vede che unusedLocalVar viene utilizzato solo in un posto, vale a dire come un argomento al costruttore WeakReference? cioè c'è qualche possibilità che l'asserzione in Case_2 possa mai fallire?

risposta

11

Non importa ciò che fa il compilatore C# - al JITter/GC è consentito pulire i riferimenti locali quando non sono più attivi nel corpo del metodo. Guarda i documenti per GC.KeepAlive

Inoltre, questo powerpoint presentation, in particolare dalla diapositiva 30 in poi, aiuta a spiegare cosa può ottenere JIT/GC.

+4

Si noti inoltre che, nelle build di debug, la variabile viene mantenuta in modo esplicito alla fine dell'ambito per consentire al debugger di essere visualizzato - è solo nelle build di rilascio che verrà visualizzato questo comportamento. –

+0

@Andy - punto interessante. Non che sia importante, ma immagino che questo comportamento sia governato dal JITter? –

+4

E per completezza, ecco perché l'impostazione di 'unusedLocalVar = null' al _end_ del metodo è solitamente una de-ottimizzazione. –

3

Mentre la mia domanda è stato risposto, ho pensato di postare questo pezzo rilevante di informazioni che ho appena trovato su MSDN blog articolo "WP7: When does GC Consider a Local Variable as Garbage" da abhinaba:

[L] a specifica ECMA (ECMA 334 sezione 10.9) [& hellip;] stati

“per esempio, se una variabile locale che è portata è l'unico riferimento esistente a un oggetto, ma variabile locale non è mai cui eventuale prosecuzione dell'esecuzione da l'attuale punto di esecuzione nella procedura, a l'implementazione potrebbe (ma non è obbligatorio) trattare l'oggetto come non più in uso. "

Questo dice tutto. L'articolo citato afferma anche che il framework .NET (almeno in modalità Release) eseguirà analisi predittive e libererà tali oggetti, mentre .NET Compact Framework non lo farà (per ragioni di prestazioni).

0

È un conforme compilatore C# permesso di ottimizzare le prime due righe di Case_2 in quelle di Case_1 se vede che unusedLocalVar viene utilizzato solo in un posto, vale a dire come un argomento al costruttore WeakReference?

Le due definizioni sono equivalenti, quindi la trasformazione da una all'altra non è un "ottimizzazione" perché nessuno dei due è più efficiente.

Esiste quindi la possibilità che l'affermazione in Case_2 possa mai fallire?

Sì. Un compilatore di produzione non è in grado di conservare un riferimento inutilmente, quindi verrà rimosso, il GC non lo vedrà come una radice globale e raccoglierà quell'oggetto.

Si noti che i garbage collector non visualizzano il programma in termini di variabili e ambito. Questi concetti di alto livello sono stati compilati da tempo prima che il codice arrivi al garbage collector. Il GC vede solo registri, stack di thread e variabili globali.