Nota
L'accesso a questa pagina richiede l'autorizzazione. È possibile provare ad accedere o modificare le directory.
L'accesso a questa pagina richiede l'autorizzazione. È possibile provare a modificare le directory.
La gestione automatica della memoria è uno dei servizi offerti da Common Language Runtime durante l'esecuzione gestita. Il Garbage Collector di Common Language Runtime gestisce l'allocazione e il rilascio della memoria per un'applicazione. Per gli sviluppatori, ciò significa che non è necessario scrivere codice per eseguire attività di gestione della memoria quando si sviluppano applicazioni gestite. La gestione automatica della memoria può eliminare i problemi comuni, ad esempio dimenticare di liberare un oggetto e causare una perdita di memoria o tentare di accedere alla memoria per un oggetto già liberato. In questa sezione viene descritto come il Garbage Collector alloca e rilascia memoria.
Allocazione della memoria
Quando si inizializza un nuovo processo, per tale processo viene riservata una regione contigua di spazio degli indirizzi. Lo spazio degli indirizzi riservato viene definito heap gestito. Nell'heap gestito viene conservato un puntatore all'indirizzo in cui verrà allocato il successivo oggetto dell'heap. Le impostazioni iniziali del puntatore corrispondono all'indirizzo di base dell'heap gestito. Tutti i tipi di riferimento vengono allocati nell'heap gestito. Quando il primo tipo di riferimento viene creato da un'applicazione, per tale tipo viene allocata memoria nell'indirizzo di base dell'heap gestito. Quando l'applicazione crea l'oggetto successivo, il garbage collector alloca la memoria nello spazio degli indirizzi immediatamente successivo al primo oggetto. Finché lo spazio degli indirizzi è disponibile, il Garbage Collector continua ad allocare spazio per i nuovi oggetti in questo modo.
L'allocazione della memoria dall'heap gestito risulta più veloce dell'allocazione di memoria non gestita. Poiché il runtime alloca memoria per un oggetto aggiungendo un valore a un puntatore, è quasi veloce quanto l'allocazione della memoria dallo stack. Inoltre, poiché i nuovi oggetti allocati consecutivamente vengono archiviati in modo contiguo nell'heap gestito, un'applicazione può accedere agli oggetti molto rapidamente.
Rilascio della memoria
Il modulo di ottimizzazione del Garbage Collector consente di determinare il momento migliore per l'esecuzione di una raccolta sulla base delle allocazioni in corso. Durante l'esecuzione di una raccolta, la memoria per gli oggetti non più utilizzati dall'applicazione viene rilasciata dal Garbage Collector. Determina quali oggetti non vengono più usati esaminando le radici dell'applicazione. Ogni applicazione ha un set di radici. Ogni radice fa riferimento a un oggetto dell'heap gestito o è impostata su null. Le radici di un'applicazione includono campi statici, variabili locali e parametri nello stack di un thread e registri della CPU. Il Garbage Collector ha accesso all'elenco di radici attive gestite dal compilatore JIT (Just-In-Time) e dal runtime. Usando questo elenco, esamina le radici di un'applicazione e nel processo crea un grafico che contiene tutti gli oggetti raggiungibili dalle radici.
Gli oggetti non presenti nel grafico non sono raggiungibili dalle radici dell'applicazione. Il Garbage Collector considera spazzatura gli oggetti non raggiungibili e rilascerà la memoria allocata per essi. Nel corso di una raccolta, l'heap gestito viene esaminato dal Garbage Collector, alla ricerca dei blocchi di spazi degli indirizzi occupati da oggetti non raggiungibili. Quando un oggetto non raggiungibile viene rilevato, viene utilizzata una funzione di copia della memoria che consente di ricompattare lo spazio allocato per gli oggetti ancora raggiungibili nella memoria, liberando i blocchi di spazi degli indirizzi allocati per oggetti non raggiungibili. Una volta compattata la memoria per gli oggetti non raggiungibili, il Garbage Collector aggiorna i puntatori agli oggetti ai rispettivi nuovi indirizzi, in modo che le radici dell'applicazione puntino agli oggetti nelle rispettive nuove posizioni. Il puntatore relativo all'heap gestito viene inoltre posizionato dopo l'ultimo oggetto non raggiungibile. Si noti che la memoria viene compattata solo se una raccolta rileva un numero significativo di oggetti non raggiungibili. Se dopo una raccolta tutti gli oggetti nell'heap gestito sopravvivono, non è necessario effettuare la compattazione della memoria.
Per migliorare le prestazioni, la memoria per oggetti di grandi dimensioni viene allocata da Common Language Runtime in un heap separato. La memoria per oggetti di grandi dimensioni viene rilasciata automaticamente dal Garbage Collector. Tuttavia, per evitare lo spostamento di oggetti di grandi dimensioni in memoria, questa memoria non viene compattata.
Generazioni e prestazioni
Per ottimizzare le prestazioni del Garbage Collector, l'heap gestito è suddiviso in tre generazioni: 0, 1 e 2. L'algoritmo di gestione della memoria del runtime si basa su diverse generalizzazioni che l'industria del software ha scoperto essere vere sperimentando con schemi di raccolta dei rifiuti. In primo luogo, è più veloce compattare la memoria per una parte dell'heap gestito rispetto all'intero heap gestito. In secondo luogo, gli oggetti più recenti avranno durate più brevi e gli oggetti meno recenti avranno durate più lunghe. Infine, gli oggetti più recenti tendono a essere correlati l'uno all'altro e a cui l'applicazione accede contemporaneamente.
Il Garbage Collector del runtime archivia nuovi oggetti nella generazione 0. Gli oggetti creati nelle prime fasi della durata dell'applicazione che non vengono raccolti vengono promossi e archiviati nelle generazioni 1 e 2. Il processo di promozione di oggetti è descritto più avanti in questo argomento. Poiché è più veloce compattare una parte dell'heap gestito rispetto all'intero heap, questo schema consente al Garbage Collector di rilasciare la memoria in una generazione specifica anziché rilasciare la memoria per l'intero heap gestito ogni volta che esegue una raccolta.
In realtà, il Garbage Collector esegue una raccolta quando la generazione 0 è piena. Se un'applicazione tenta di creare un nuovo oggetto quando la generazione 0 è piena, Il Garbage Collector rileva che non vi è spazio di indirizzi rimanente nella generazione 0 da allocare per l'oggetto. Il Garbage Collector esegue una raccolta nel tentativo di liberare spazio di indirizzi nella generazione 0 per l'oggetto. Il Garbage Collector esamina prima di tutto gli oggetti presenti nella generazione 0, anziché tutti gli oggetti presenti nell'heap gestito. Questo è l'approccio più efficiente, perché i nuovi oggetti tendono a avere durate brevi ed è previsto che molti degli oggetti nella generazione 0 non saranno più in uso dall'applicazione quando viene eseguita una raccolta. Inoltre, una raccolta di generazione 0 da sola recupera memoria sufficiente per consentire all'applicazione di continuare a creare nuovi oggetti.
Dopo che il Garbage Collector esegue una raccolta di generazione 0, compatta la memoria per gli oggetti raggiungibili, come illustrato in Rilascio della memoria in precedenza in questo argomento. Il Garbage Collector promuove quindi questi oggetti e considera questa parte dell'heap gestito generazione 1. Poiché la durata degli oggetti non raccolti è solitamente più lunga, la promozione a una generazione superiore risulta opportuna. Di conseguenza, il collettore dei rifiuti non deve riesaminare gli oggetti delle generazioni 1 e 2 ogni volta che esegue una collezione della generazione 0.
Dopo che il Garbage Collector esegue la prima raccolta degli elementi nella generazione 0 e promuove gli oggetti raggiungibili alla generazione 1, considera il resto dell'heap gestito nella generazione 0. Continua ad allocare memoria per i nuovi oggetti nella generazione 0 fino a quando la generazione 0 non è piena ed è necessario eseguire un'altra raccolta. A questo punto, il motore di ottimizzazione del Garbage Collector determina se è necessario esaminare gli oggetti nelle generazioni precedenti. Ad esempio, se una raccolta di generazione 0 non recupera memoria sufficiente per completare correttamente il tentativo di creazione di un nuovo oggetto, il Garbage Collector può eseguire una raccolta di generazione 1, quindi la generazione 2. Se non viene recuperata abbastanza memoria, il garbage collector può eseguire una raccolta delle generazioni 2, 1 e 0. Dopo ogni raccolta, il garbage collector compatta gli oggetti raggiungibili nella generazione 0 e li trasferisce alla generazione 1. Gli oggetti presenti nella generazione 1 non raccolti vengono promossi alla generazione 2. Poiché il Garbage Collector supporta solo tre generazioni, gli oggetti nella generazione 2 che continuano a esistere dopo una raccolta rimangono nella generazione 2 fino a quando non vengono considerati irraggiungibili in una raccolta futura.
Rilascio della memoria per le risorse non gestite
Per la maggior parte degli oggetti creati dall'applicazione, è possibile affidarsi al Garbage Collector per eseguire automaticamente le attività di gestione della memoria necessarie. Per le risorse non gestite è tuttavia necessario il rilascio esplicito. Il tipo più comune di risorsa non gestita è rappresentato da un oggetto che esegue il wrapping di una risorsa del sistema operativo, quale un handle di file, un handle di finestra o una connessione di rete. Anche se il Garbage Collector è in grado di tenere traccia della durata di un oggetto gestito che incapsula una risorsa non gestita, non ha conoscenze specifiche su come pulire la risorsa. Quando si crea un oggetto che incapsula una risorsa non gestita, è consigliabile fornire il codice necessario per pulire la risorsa non gestita in un metodo Dispose pubblico. Fornendo un metodo Dispose , si consente agli utenti dell'oggetto di liberare esplicitamente la memoria al termine dell'oggetto. Quando si usa un oggetto che incapsula una risorsa non gestita, è necessario conoscere Dispose e chiamarlo in base alle esigenze. Per altre informazioni sulla pulizia delle risorse non gestite e su un esempio di modello di progettazione per l'implementazione di Dispose, vedere Garbage Collection.