GCは、予測可能で予約されたリソースを扱います。VMはVMを完全に制御し、作成するインスタンスと作成するインスタンスを完全に制御します。ここのキーワードは「予約」と「トータルコントロール」です。ハンドルはOSによって割り当てられ、ポインターは...管理領域外に割り当てられたリソースへのポインターです。そのため、ハンドルとポインターは、マネージコード内での使用に制限されません。それらは、同じプロセスで実行されるマネージコードとアンマネージコードによって使用でき、多くの場合は使用できます。
「リソースコレクター」は、ハンドル/ポインターがマネージドスペース内で使用されているかどうかを確認できますが、定義上、メモリスペースの外で何が起こっているかを認識していません(さらに、いくつかのハンドルを使用すると、事態が悪化します)プロセスの境界を越えて)。
実用的な例は.NET CLRです。フレーバー付きC ++を使用して、マネージメモリスペースとアンマネージメモリスペースの両方で機能するコードを記述できます。ハンドル、ポインタ、参照は、マネージコードとアンマネージコードの間で受け渡しできます。アンマネージコードは、CLRがそのマネージリソースに対して行われた参照を追跡し続けることができるように、特別な構成要素/型を使用する必要があります。しかし、それができる最善の方法です。ハンドルとポインターを使用して同じことを行うことはできません。そのため、リソースコレクターは、特定のハンドルまたはポインターを解放してもよいかどうかはわかりません。
編集:.NET CLRに関しては、.NETプラットフォームでのC ++開発の経験はありません。おそらく、CLRがマネージコードとアンマネージコードの間のハンドル/ポインターへの参照を追跡し続けることを可能にする特別なメカニズムがあるはずです。その場合は、CLRがそれらのリソースの有効期間を処理し、それらへのすべての参照がクリアされたときにそれらを解放できます(少なくとも一部のシナリオでは可能です)。どちらの方法でも、ベストプラクティスでは、ハンドル(特にファイルを指すもの)とポインターは、必要がなくなったらすぐに解放するように指示されています。リソースコレクターはこれに準拠していません。これが、リソースコレクターがない理由の1つです。
編集2:管理された領域内でのみ使用される場合に特定のハンドルを解放するコードを記述することは、CLR / JVM / VMs-in-generalでは比較的簡単です。.NETでは次のようになります。
// 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);