GC si occupa di una risorsa prevedibile e riservata . La VM ha il controllo totale su di essa e ha il controllo totale su quali istanze vengono create e quando. Le parole chiave qui sono "riservato" e "controllo totale". I gestori sono allocati dal sistema operativo e i puntatori sono ... bene puntatori a risorse allocate al di fuori dello spazio gestito. Per questo motivo, handle e puntatori non sono limitati per essere utilizzati all'interno del codice gestito. Possono essere utilizzati - e spesso lo sono - da codice gestito e non gestito in esecuzione sullo stesso processo.
Un "raccoglitore di risorse" sarebbe in grado di verificare se un handle / pointer viene utilizzato o meno all'interno di uno spazio gestito, ma per definizione non è a conoscenza di ciò che sta accadendo al di fuori del suo spazio di memoria (e, per peggiorare le cose, è possibile utilizzare alcuni handle oltre i confini del processo).
Un esempio pratico è il CLR .NET. Si può usare il C ++ aromatizzato per scrivere codice che funziona con spazi di memoria sia gestiti che non gestiti; handle, puntatori e riferimenti possono essere passati tra codice gestito e non gestito. Il codice non gestito deve utilizzare costrutti / tipi speciali per consentire al CLR di tenere traccia dei riferimenti fatti alle sue risorse gestite. Ma è il massimo che può fare. Non può fare lo stesso con handle e puntatori, e per questo motivo il suddetto Resource Collector non saprebbe se va bene rilasciare un handle o un puntatore particolare.
modifica: per quanto riguarda il CLR .NET, non ho esperienza con lo sviluppo di C ++ con la piattaforma .NET. Forse esistono meccanismi speciali che consentono al CLR di tenere traccia dei riferimenti a handle / puntatori tra codice gestito e non gestito. In tal caso, il CLR potrebbe occuparsi della vita di quelle risorse e rilasciarle quando vengono cancellati tutti i riferimenti (beh, almeno in alcuni scenari potrebbe). Ad ogni modo, le migliori pratiche impongono che handle (specialmente quelli che puntano a file) e puntatori debbano essere rilasciati non appena non sono necessari. Un Collezionista di risorse non si conformerebbe a ciò, questa è un'altra ragione per non averne uno.
modifica 2: È relativamente banale su CLR / JVM / VM in generale scrivere del codice per liberare un determinato handle se viene utilizzato solo all'interno dello spazio gestito. In .NET sarebbe qualcosa di simile:
// This class offends many best practices, but it would do the job.
public class AutoReleaseFileHandle {
// keeps track of how many instances of this class is in memory
private static int _toBeReleased = 0;
// the threshold when a garbage collection should be forced
private const int MAX_FILES = 100;
public AutoReleaseFileHandle(FileStream fileStream) {
// Force garbage collection if max files are reached.
if (_toBeReleased >= MAX_FILES) {
GC.Collect();
}
// increment counter
Interlocked.Increment(ref _toBeReleased);
FileStream = fileStream;
}
public FileStream { get; private set; }
private void ReleaseFileStream(FileStream fs) {
// decrement counter
Interlocked.Decrement(ref _toBeReleased);
FileStream.Close();
FileStream.Dispose();
FileStream = null;
}
// Close and Dispose the Stream when this class is collected by the GC.
~AutoReleaseFileHandle() {
ReleaseFileStream(FileStream);
}
// because it's .NET this class should also implement IDisposable
// to allow the user to dispose the resources imperatively if s/he wants
// to.
private bool _disposed = false;
public void Dispose() {
if (_disposed) {
return;
}
_disposed = true;
// tells GC to not call the finalizer for this instance.
GC.SupressFinalizer(this);
ReleaseFileStream(FileStream);
}
}
// use it
// for it to work, fs.Dispose() should not be called directly,
var fs = File.Open("path/to/file");
var autoRelease = new AutoReleaseFileHandle(fs);