Un GC si occupa di liberare la memoria allocata ma non più necessaria per renderla nuovamente disponibile.
Alcuni linguaggi sono progettati per usare un GC, sono stati pensati così e perciò materialmente non possono essere implementati senza.
Linguaggi come il C++ distruggono gli oggetti allocati all'uscita da uno scope. Java e C# invece, ad esempio, all'uscita dallo scope non fanno nulla se non "prendere atto che nulla punta più agli oggetti allocati". La memoria non viene quindi liberata, verrà liberata solo quando il GC lo riterrà necessario.
Altri esempi in cui senza un GC non sarebbe possibile un'implementazione (a meno di memoria infinita) sono i linguaggi funzionali.
In generale ogni linguaggio dove gli oggetti non hanno un lifetime prestabilito necessita di un GC (free è di fatto prestabilire la liberazione della memoria).
La presenza di un GC introduce il problema opposto: non conoscere il lifetime degli oggetti. Questo nella maggior parte dei casi non ti da alcun problema, ma in presenza di risorse speciali che devi assicurarti di rilasciare sempre è un problema. Un esempio: se utilizzi un file all'interno di una funzione in C++ sarai sicuro che all'uscita dalla funzione il file sarà liberato, in C# e Java no. E' a questo scopo che nascono keywords quale using in C# che viene tradotta con un try-finally che si assicura che venga sempre chiamata la funzione .Dispose() che libera le risorse di fatto invalidando l'oggetto, ma senza distruggerlo (ovvero, l'oggetto rimane allocato, vengono solo liberate le risorse speciali).
editSì, puoi sempre implementare un GC se non è disponibile con vari compromessi.
@MItaly si può dire che il reference counting sia la più facile forma di GC, infatti basta scrivere una funzione che utilizzi per l'assegnazione e una funzione per scartare i valori di ritorno non utilizzati.
Questo assumendo non siano presenti cicli, in questo caso quegli oggetti rimarrebbero fino all'uscita, dove la memoria sarebbe comunque liberata dal sistema.

Rispondi quotando