Attuando il processo di ''garbage collection'' l'ambiente nel quale viene eseguito il programma gestisce la memoria automaticamente, liberando il [[programmatore]] dalla necessità di prevedere quando rilasciare le risorse utilizzate da un oggetto non più necessario all'[[elaborazione dati|elaborazione]]. Tale modalità automatica migliora la stabilità dei programmi in quanto consente di evitare quella classe di [[bug]] connessi all'utilizzo di puntatori alle varie aree di memoria già liberate in passato.<ref>Tecnicamente chiamato il problema dei '[[dangling pointer]]s'.</ref>
Alcuni [[linguaggio di programmazione|linguaggi di programmazione]], come [[Java (linguaggio di programmazione)|Java]], [[Python]] e [[C sharp|C#]] ([[.NET]]), hanno un sistema di ''garbage collection'' integrato direttamente nell'ambiente di esecuzione, mentre per altri linguaggi, come il [[C (linguaggio)|C]] e il [[C++]], la sua eventuale implementazione è a carico del programmatore. Tuttavia molti linguaggi di programmazione utilizzano una combinazione dei due approcci, come [[Ada (linguaggio)|Ada]], [[Modula-3]] e [[Common Language Infrastructure|CLI]], consentono all'utente di eliminare manualmente gli oggetti, o, volendo velocizzare il processo, addirittura disattivare la gestione automatica del sistema '''GC'''. La garbage collection è quasi sempre strettamente integrata con l'[[Allocazione dinamica della memoria|allocazione di memoria]].
=== Benefici ===
La ''garbage collection'' esonera il programmatore dall'eseguire manualmente l'allocazione (richiesta) e la delocazione (rilascio) di aree di memoria, riducendo o eliminando del tutto alcune categorie di bugsbug:
* ''[[Dangling pointer|'''Dangling pointers''']]'': persistenza nel programma di puntatori che si riferiscono ad aree di memoria che contenevano oggetti, ormai delocate. Utilizzare tali aree di memoria delocate può, nel migliore dei casi, provocare un errore fatale dell'applicazione, ma si possono manifestare altri problemi anche a distanza di tempo dalla effettiva delocazione. La risoluzione di questi problemi può essere molto difficoltosa.
* '''''Doppia deallocazione''''': il programma tenta di liberare nuovamente una zona di memoria già rilasciata.
* '''''Alcuni tipi di [[memory leak]]s'':''' il programma perde traccia di alcune aree di memoria allocate<ref>Ad esempio nel caso in cui il puntatore ad esse viene modificato.</ref>, perdendo la possibilità di deallocarle nel momento in cui non servono più. Questo tipo di problema può accumularsi nel corso dell'esecuzione del programma, portando, nel corso del tempo, all'esaurimento della memoria disponibile.
La maggior parte degli errori di programmazione nei linguaggi che non prevedono la garbage collection, o quando la stessa venga volontariamente disattivata, rientrano nei casi sopra descritti.
La ''garbage collection'' presenta tuttavia anche alcuni svantaggi:
* '''Consumo di risorse di calcolo''' : il processo consuma risorse di calcolo, al fine sia di tenere traccia dell'utilizzo delle varie aree di memoria, sia di poter decidere il momento e la quantità di memoria da liberare;
* '''Incertezza del momento in cui viene effettuata la Garbage Collection''': Il momento in cui viene effettuata tale operazione non è prevedibile: questa incertezza può determinare improvvisi blocchi o ritardi nell'esecuzione. Problemi di questo genere sono inaccettabili in ambienti [[sistema real-time|real-time]], nel rilevamento di [[driver|driver periferici]], e nell'[[transaction processing|elaborazione di transazioni]];
* '''Rilascio della memoria non deterministico''': analogamente, sia il momento in cui una data area di memoria viene rilasciata, sia l'ordine di rilascio delle varie aree non più utilizzate, dipendono dal particolare [[algoritmo]] implementato dal ''garbage collector''. Si può dire che il rilascio di memoria avviene in modo non deterministico.
* '''Presenza di memory leak''': i [[memory leak]], perdita o fuoriuscita di memoria, possono comunque verificarsi, nonostante la presenza di un '''Garbage Collector.''' Ciò può accadere se il programma mantiene un riferimento ad oggetti che hanno esaurito il loro ciclo logico di vita nell'applicazione. La presenza di riferimenti attivi comporta l'impossibilità da parte del collector di rilevare l'area di memoria come non utilizzata.<ref>{{cita pubblicazione |autore= Maebe Jonas |coautori= Ronsse Michiel, De Bosschere Koen|titolo=Precise detection of memory leaks|url=https://www.cs.virginia.edu/woda2004/papers/maebe.pdf|accesso=13 maggio 2010}}</ref> Questo può verificarsi, ad esempio, con collezioni di oggetti. Il monitoraggio del ciclo di vita degli oggetti è una responsabilità primaria dello sviluppatore in ambienti ''garbage-collected''.
== Tracing garbage collection ==
=== Raggiungibilità di un oggetto ===
Siano "'''p'''" e "'''q'''" due oggetti, e sia q un oggetto raggiungibile. Diremo che p è raggiungibile in maniera ricorsiva, se e solo se esiste un riferimento ad esso tramite l'oggetto q (ovvero p è raggiungibile attraverso un oggetto q, a sua volta raggiungibile). Un oggetto può essere raggiungibile solo in due casi:
* Quando viene creato all'avvio del programma (oggetto globale) o di una sua sotto-procedura (oggetti di [[scope]], creati sullo [[Pila (informatica)|stack]]); l'oggetto in questione viene detto in tal caso '''radice''';
* Quando un altro oggetto, raggiungibile, trattiene un riferimento ad esso; in modo più formale, la raggiungibilità è una ''chiusura transitiva''.
L'identificazione delle aree di memoria ''spazzatura'' con quelle non raggiungibili non è ottimale, in quanto potrebbe accadere che un programma utilizzi per l'ultima volta una certa area molto prima che questa diventi irraggiungibile. A volte si distingue perciò fra spazzatura '''sintattica''', quando l'oggetto ''non può'' essere raggiunto dal programma, e '''semantica''', quando il programma ''non vuole'' più utilizzare l'oggetto. Ad esempio:
<syntaxhighlight lang="java">
Object x = new Foo();
</syntaxhighlight>
Il problema di individuare precisamente la spazzatura semantica è purtroppo solo parzialmente [[decidibilità|decidibile]]: dall'esempio mostrato sopra, infatti, è chiaro che l'identificazione positiva di un oggetto come spazzatura semantica dipende dal fatto che le elaborazioni precedenti terminino correttamente in un tempo finito. Ciò comporta che un collector che volesse identificare la spazzatura semantica dovrebbe poter decidere, sempre in un tempo finito, se una certa procedura termini ([[problema della fermata]]). Pertanto, essenzialmente tutti i collectorscollector implementati si concentrano sulla spazzatura sintattica.
=== Algoritmo di base ===
I '''''Tracing collector''''' sono algoritmi dedicati, in quanto in grado di tracciare il set di lavoro della memoria, effettuando ciclicamente la raccolta degli oggetti non più necessari. Un ciclo viene avviato quando il Garbage Collector stabilisce di avere la necessità di recuperare memoria; ciò accade più frequentemente quando il sistema è in memoria bassa. Il metodo originale prevede un '''mark-and-sweep'''<ref>Trad.Ing.:"''Marca e butta via''"</ref> in cui il set di memoria viene più volte analizzato.
==== Naïve mark-and-sweep ====
Nel ''mark-and-sweep'' ogni oggetto in memoria possiede un [[flag]], in genere è sufficiente un [[bit]], riservato esclusivamente per l'utilizzo del Garbage Collector. Quando l'oggetto viene creato, il [[flag]] viene posto in stato, ''flag clear''<ref name=":0">Trad.Ing.:"''Non in uso''"</ref>.
Durante la prima fase, o '''fase di Mark''', del ciclo di Garbage Collection, viene scansionato l'intero set di [[Root (informatica)|root]], ponendo ogni oggetto in stato di ''flag set.''<ref name=":1">Trad.Ing.:"''In Uso''"</ref> Tutti gli oggetti accessibili dalla radice del set sono anch'essi contrassegnati come in stato di ''flag set''.<ref name=":1" />
Nella seconda fase, o '''fase di Sweep''', ogni oggetto in memoria viene ancora una volta esaminato; quelli che hanno ancora il ''flag clear''<ref name=":0" /> non sono raggiungibili da nessun programma o dato, e la loro memoria viene quindi liberata. Per gli oggetti che sono marcati flag set, il flag viene posto in stato ''flag clear''<ref name=":0" />, preparandoli per il prossimo ciclo di Garbage Collection.
Questo metodo ha diversi svantaggi, per esempio, l'intero sistema viene sospeso durante la Garbage Collection in modo non sempre prevedibile e per periodi di tempo non determinabili a priori; questo tipo di comportamento può creare notevoli problemi in ambienti che necessitano di basse [[Latenza|latenze]] di risposta o in [[Sistema real-time|sistemi real-time]] o mission critical, con possibili malfunzionamenti, [[deadlock]], e arresti che possono compromettere l'intero sistema. Inoltre, tutta la memoria di lavoro deve essere esaminata, minimo due volte, causando potenzialmente problemi nei sistemi a [[memoria virtuale|memoria paginata]].
==== Tri-colour marking ====
A causa di questi svantaggi gli algoritmi più moderni di ''garbage collection'' attuano delle varianti rispetto a semplici meccanismi, quali il ''mark-and-sweep'', applicando algoritmi del tipo '''tri-colour marking'''. L'algoritmo effettua marcature su tre diversi livelli secondo le seguenti fasi:
# '''Crea set di livelli di bianco, grigio e nero''' utilizzati per segnare i vari progressi effettuati durante il ciclo.
#* Il '''set bianco''' è l'insieme di oggetti candidati al riciclo.
#* Il '''set nero''' è l'insieme di oggetti privi di riferimenti in uscita a oggetti del set bianco, raggiungibili dalla radice. Gli oggetti del set nero non sono candidati per essere riciclati; in molte implementazioni, il set nero inizia come vuoto.
#* Il '''set grigio''' contiene tutti gli oggetti raggiungibili dalla radice, ma che ancora devono essere sottoposti a scansione per controllare se hanno riferimenti in uscita agli oggetti "bianchi". Dal momento che sono noti per essere raggiungibile dalla radice, non possono essere riciclati e finiranno nel set nero dopo essere stati sottoposti a scansione. Il set grigio è inizializzato con gli oggetti direttamente riferiti dalla radice; in genere tutti gli altri oggetti sono inizialmente posizionati nel set bianco.
#* Gli oggetti possono passare soltanto dal bianco al grigio e dal grigio al nero ma non in senso opposto.
# '''Raccoglie gli oggetti dal set di grigio''' e sposta questi nel set di nero (Blacken) se questi non possono essere garbage collected.
# '''Ripete i vari passaggi''' fino a quando il set di grigio diventa vuoto.
# '''Quando non vi sono più oggetti nel set di grigio''', per tutti i rimanenti oggetti nel set bianco è stato dimostrato che non sono raggiungibili per cui lo spazio di memoria da essi occupato viene recuperato.
Dal momento che tutti gli oggetti non immediatamente raggiungibili dalla radice sono tipicamente assegnati al set di bianco, e gli oggetti possono muoversi solo dal bianco al grigio e dal grigio al nero, l'algoritmo conserva un [[Invarianza|invariante]] importante - ''nessun oggetto nero punta direttamente ad un oggetto bianco''. Questo garantisce che gli oggetti bianchi possono essere distrutti in modo sicuro una volta che il set grigio è vuoto.
L'algoritmo presenta un vantaggio importante: può essere eseguito '''''on-the-fly,''''', senza che sia arrestato il sistema per periodi di tempo significativo. Ciò si ottiene marcando gli oggetti nel momento in cui vengono allocati e durante le modifiche, mantenendo i tre insiemi. Monitorando la dimensione degli insiemi, il sistema può effettuare ''garbage collection'' periodicamente o quando necessario. Inoltre, viene eliminata la necessità di toccare l'intero insieme degli oggetti durante ciascun ciclo di Garbage Collected.
=== Strategia di attuazione ===
Al fine di attuare l'algoritmo ''tri-colour marking'' si prendono importanti decisioni al momento della progettazione e ciò può incidere sensibilmente sulle caratteristiche delle prestazioni del garbage collector.
==== Movimento contro non movimento ====
Una volta che il set è stato classificato irraggiungibile, il Garbage Collector può semplicemente rilasciare gli oggetti irraggiungibili, oppure copiare alcuni o tutti gli oggetti raggiungibili in una nuova area di memoria, aggiornando tutti i riferimenti a tali oggetti come necessario. Questi sono chiamati rispettivamente collettor in '''''non movimento''''' ed '''''in movimento'''''.
A prima vista una strategia di Garbage Collector in movimento può sembrare inefficiente e costosa rispetto all'approccio di ''non movimento'', dato che sembra essere richiesto molto più tempo di elaborazione per ogni ciclo. In realtà, la strategia in movimento porta a diversi vantaggi in termini di prestazioni, sia durante il ciclo di raccolta dei rifiuti, che durante l'esecuzione del programma vero e proprio:
* Oggetti che fanno riferimento l'uno all'altro spesso possono essere spostati in locazioni di memoria adiacenti, aumentando la probabilità che questi si trovino sulla stessa linea della [[cache]] o della pagina di [[RAM|memoria virtuale]]. Questo accelererà notevolmente l'accesso ai nuovi oggetti attraverso i riferimenti.
Uno svantaggio del ''Garbage Collection in movimento'' è che consente l'accesso solo attraverso i riferimenti gestiti dai riferimenti dei rifiuti, impedendo l'[[aritmetica dei puntatori]]. Ciò accade perché i puntatori iniziali non sono più validi dal momento in cui il Garbage Collector sposta l'oggetto, diventeranno puntatori sospesi. Per l'[[Interoperabilità|interaoperabilitàinteroperabilità]] con il [[codice nativo]], il Garbage Collector deve copiare la posizione dei contenuti dell'oggetto al di fuori della regione di memoria che contiene i rifiuti. Un approccio alternativo consiste nel salvare l'oggetto in memoria con un codice pin, impedendo al Garbage Collector di muoversi, consentendo ai puntatori nativi di lavorare direttamente con la memoria ed eventualmente consentendo l'aritmetica dei puntatori.<ref>{{Cita web
|url = https://msdn.microsoft.com/en-us/library/23acw07k.aspx
|titolo = Copying and Pinning
==== La copia mark-and-sweep contro la copia mark-and-don't-sweep ====
Come abbiamo già visto, per raffinare ulteriormente la distinzione, i collettorcollector possono tracciare gli oggetti secondo tre set (bianco, grigio e nero) e mantenerli durante il ciclo di raccolta. L'approccio più semplice è stato inventato nel 1969 e prende il nome di '''semi-space collector.'''. In questo schema di Garbage Collector in movimento, la memoria è divisa in due parti: "''dallo spazio" e "allo spazio"''. Inizialmente gli oggetti sono assegnati ''"allo spazio"'' fino a quando non diventeranno oggetti a pieno titolo e la collezione attivata. All'inizio lo stato "allo spazio" diventa "dallo spazio" e viceversa, e gli oggetti raggiungibili dalla radice vengono copiati dallo spazio allo spazio. Questi oggetti vengono scansionati a turno e tutti gli oggetti a cui puntano vengono copiati allo spazio fino a quando tutti gli oggetti raggiungibili sono stati copiati in questa parte. Questo approccio ha il vantaggio di essere semplice concettualmente (i tre set sono costruiti durante il processo di copia), ma uno svantaggio è che ad ogni ciclo di raccolta viene richiesta una grande regione contigua di memoria libera. La tecnica è conosciuta anche come stop-and-copy. Un ulteriore miglioramento rispetto al semi-space collector è ''l'<nowiki/>'''algoritmo di Cheney'''.''<ref>{{Cita web|url=http://pages.di.unipi.it/ferrari/CORSI/PR2/LEZIONI2014/PR2GC.pdf|titolo=Algoritmo di Chaney}}</ref>
Un '''mark-and-sweep''' garbage collection, mantiene uno o due bit per ogni oggetto da registrare. L'albero di riferimento viene attraversato nel corso di un ciclo di raccolta (fase di mark) e gli oggetti vengono manipolati dal collettor per riflettere lo stato attuale e la fase di sweep libera la memoria. Il mark-and-sweep ha il vantaggio che, una volta determinato il set irraggiungibile, non può essere attuata né una strategia di movimento, né una strategia di non movimento.
Un '''mark-and-don't-sweep''' garbage collection come il precedente, mantiene un bit per ogni oggetto da registrare, vi sono però due differenze fondamentali: innanzitutto il set di bianco e nero hanno significato diverso da quello del mark-and-sweep, poiché in quest'ultimo sistema tutti gli oggetti raggiungibili sono sempre di colore nero. Un oggetto contrassegnato come nero rimarrà tale anche se diventa irraggiungibile. Un oggetto bianco è attribuito come inutilizzabile. In secondo luogo l'interpretazione di nero/bianco può variare (0=bianco, 1= nero) e viceversa.
==== Generational Garbage Collector (Ephemeral Garbage Collector) ====
==== Stop-the-world contro incremental contro concurrent ====
Il meccanismo '''stop-the-world''' opera semplicemente interrompendo l'esecuzione del ciclo di raccolta in modo da garantire che i nuovi oggetti non siano assegnati e non diventino improvvisamente irraggiungibili mentre il collector è in esecuzione. Svantaggio evidente è che il programma non può svolgere alcun lavoro utile mentre è in esecuzione il ciclo di raccolta (detta "embarrassing pause"). Incremental and concurrent garbage collection sono progettati per ridurre questa interruzione, svolgendo il ciclo di raccolta rifiuti in fasi distinte rispetto all'esecuzione del programma. L'idea di progettazione è quella di garantire che il programma non interferisca con il Garbage Collector e viceversa.
==== Precise contro conservative and internal pointers ====
In generale, [[linguaggio di programmazione ad alto livello|linguaggi di programmazione ad alto livello]] dispongono solitamente del Garbage Collector come caratteristica standard. In linguaggi che ne sono privi, spesso questo viene aggiunto tramite una libreria, come con il Garbage Collection Boehm del [[C (linguaggio)|C]] e [[C++]]. La maggior parte dei [[programmazione funzionale|linguaggi di programmazione funzionali]] come la [[standard ML|ML]], [[Haskell (linguaggio)|Haskell]] e [[APL]] hanno il Garbage Collector come caratteristica di default. Il [[Lisp]] è stato il primo linguaggio funzionale che ha introdotto questo meccanismo.
Altri linguaggi dinamici come [[Ruby (linguaggio di programmazione)|Ruby]] tendono ad usare il Garbage Collector. I [[Object oriented|linguaggi di programmazione orientati agli oggetti]], come [[Smalltalk]], [[Java (linguaggio di programmazione)|Java]] e [[ECMAScript]], solitamente prevedono il Garbage Collector integrato. Storicamente i linguaggi destinati ai principianti come [[BASIC]] utilitizzanousano spesso variabili di diversa lunghezza come stringhe e liste, in modo da sollevare il programmatore dall'onere di gestire manualmente la memoria. Il problema relativo alla velocità del sistema rallentato dall'azione del Garbage Collector aumenta notevolmente nei microcomputer.
== Ambienti limitati ==
Il Garbage Collector è raramente usato in ambienti di tipo embedded o real-time a causa dell'delle esigenze di tali ambienti. Tuttavia, sono stati sviluppati Garbage Collector compatibili per questi ambienti limitati<ref>[https://portal.acm.org/ft_gateway.cfm?id=1140392&type=pdf&coll=GUIDE&dl=GUIDE&CFID=15151515&CFTOKEN=6184618 Wei Fu and Carl Hauser, "A Real-Time Garbage Collection Framework for Embedded Systems". ACM SCOPES '05, 2005.]</ref>. Microsoft[[Microsoft .NET|.NET Micro Framework]] e [[J2ME|Java Platform, Micro Edition]] sono piattaforme di software embedded che dispongono di Garbage Collection.
== Note ==
|