I miei due centesimi sul metodo GC.Collect in C #

Il metodo GC.Collect () è stato a lungo popolare tra gli sviluppatori .Net. Tuttavia, pochi di noi sanno come funziona effettivamente o se è necessaria una chiamata.

Il CLR (Common Language Runtime) adotta la garbage collection come meccanismo per pulire le risorse consumate dall'applicazione. Tieni presente che quando crei oggetti in .Net, vengono memorizzati nell'heap gestito e, quando hai finito di utilizzarli, non devi preoccuparti di pulirli: il runtime lo farà per te.

Il CLR organizza l'heap gestito in generazioni. Le tre generazioni in cui è organizzato l'heap gestito sono: Generazione 0, Generazione 1 e Generazione 2. Il GC è in grado di recuperare la memoria occupata dagli oggetti gestiti. Tuttavia, dovresti seguire alcune linee guida per facilitare una raccolta dei rifiuti più veloce in modo da migliorare le prestazioni della tua applicazione.

Devo usare il metodo GC.Collect ()?

Prima di tutto, devi assolutamente chiamare GC.Collect nel codice della tua applicazione? La risposta nella maggior parte dei casi è no. Lascia che ora ti dica cosa fa questo metodo e perché dovresti astenervi dal chiamare questo metodo nella maggior parte dei casi.

Quando si effettua una chiamata al metodo GC.Collect (), il runtime esegue uno stack walk per determinare gli oggetti che sono raggiungibili e quelli che non lo sono. Inoltre blocca il thread principale (e anche tutti i thread secondari creati) dell'applicazione. In altre parole, quando viene chiamato il metodo GC.Collect (), il runtime esegue una garbage collection di blocco di tutte le generazioni.

Preferirei sempre non usare GC.Collect () a meno che non ci sia un motivo specifico per usarlo. Un GC consiste in genere nelle fasi Mark e Sweep seguite da una fase di compattazione. Il tempo impiegato dal runtime per eseguire un GC può diventare un collo di bottiglia, quindi usalo solo molto raramente e se ne hai davvero bisogno. Rico Mariani afferma: "Considerare la possibilità di chiamare GC.Collect () se si è appena verificato un evento non ricorrente ed è molto probabile che questo evento abbia causato la morte di molti vecchi oggetti".

Utilizzando il metodo GC.Collect ()

Ecco come puoi richiamare il metodo GC.Collect () nel tuo codice.

GC.Collect();

Tieni presente che puoi anche raccogliere oggetti che appartengono a una generazione specifica.

GC.Collect() - utilizzato per raccogliere oggetti presenti nelle generazioni 0, 1, 2

GC.Collect(0) - utilizzato per raccogliere oggetti presenti nella generazione 0

GC.Collect(1) - utilizzato per raccogliere oggetti presenti nelle generazioni 0 e

È inoltre possibile determinare la quantità di memoria liberata effettuando una chiamata al metodo GC.Collect (). Per fare ciò, puoi sfruttare il metodo System.GC.GetTotalMemory () come mostrato nello snippet di codice di seguito.

//Write code to create some large objects here

Console.WriteLine("Total available memory before collection: {0:N0}", System.GC.GetTotalMemory(false));

System.GC.Collect();

Console.WriteLine("Total available memory collection: {0:N0}", System.GC.GetTotalMemory(true));

Il metodo GC.GetGeneration () può essere utilizzato per conoscere la generazione a cui appartiene un oggetto. Fare riferimento all'elenco dei codici riportato di seguito.

static void Main(string[] args)

       {

           List obj = new List() { "Joydip", "Steve" };

           Console.WriteLine(System.GC.GetGeneration(obj));

           System.GC.Collect();

           Console.WriteLine(System.GC.GetGeneration(obj));

           System.GC.Collect();

           Console.WriteLine(System.GC.GetGeneration(obj));

           Console.Read();

       }

Quando esegui il programma sopra, ecco cosa viene stampato nella finestra della console.

0

1

2

Come puoi vedere, ogni chiamata al metodo GC.Collect () promuove l'oggetto "obj" alla successiva generazione superiore. Questo perché l'oggetto "obj" sopravvive alla garbage collection in ciascuno dei due casi, ovvero non viene recuperato in nessuna delle due chiamate effettuate al metodo GC.Collect ().

È possibile forzare la garbage collection su tutte e tre le generazioni o su una generazione specifica utilizzando il metodo GC.Collect (). Il metodo GC.Collect () è sovraccarico: puoi chiamarlo senza alcun parametro o anche passando il numero di generazione che desideri raccogliere dal garbage collector.

Notare che gli oggetti che hanno finalizzatori (e se non è stata effettuata una chiamata al metodo SuppressFinalize) non verranno raccolti quando viene effettuata una chiamata al metodo GC.Collect (). Piuttosto, tali oggetti verrebbero inseriti nella coda di finalizzazione. Se desideri raccogliere anche questi oggetti, devi effettuare una chiamata al metodo GC.WaitForPendingFinalizers () in modo che quegli oggetti vengano puliti quando viene eseguito il ciclo GC successivo. In sostanza, il recupero della memoria occupata dagli oggetti che hanno i finalizzatori implementati richiede due passaggi poiché tali oggetti vengono inseriti nella coda di finalizzazione anziché essere recuperati al primo passaggio quando viene eseguito il garbage collector.