GC 는 예측 가능하고 예약 된 리소스를 처리합니다. VM은이를 완전히 제어 할 수 있으며 생성되는 인스턴스와시기를 완벽하게 제어 할 수 있습니다. 여기에있는 키워드는 "예약 된"및 "전체 제어"입니다. 핸들은 OS에 의해 할당되고 포인터는 관리 공간 외부에 할당 된 리소스에 대한 포인터입니다. 따라서 핸들과 포인터는 관리 코드 내에서 사용하도록 제한되지 않습니다. 그것들은 같은 프로세스에서 실행되는 관리 코드와 관리되지 않는 코드에 의해 사용될 수 있으며 종종 있습니다.
"리소스 콜렉터"는 핸들 / 포인터가 관리 공간 내에서 사용 중인지 여부를 확인할 수 있지만, 정의 상으로는 메모리 공간 외부에서 발생하는 일을 인식하지 못하며 (일부 상황을 악화시키기 위해 일부 핸들을 사용할 수 있음) 공정 경계를 넘어).
실제 예는 .NET CLR입니다. 풍미있는 C ++를 사용하여 관리되는 메모리 공간과 관리되지 않는 메모리 공간 모두에서 작동하는 코드를 작성할 수 있습니다. 핸들, 포인터 및 참조는 관리 코드와 관리되지 않는 코드 사이에서 전달 될 수 있습니다. 관리되지 않는 코드는 CLR이 관리되는 리소스에 대한 참조를 계속 추적 할 수 있도록 특수한 구성 / 유형을 사용해야합니다. 그러나 그것이 최선을 다하는 것입니다. 핸들과 포인터로도 같은 작업을 수행 할 수 없으며, 따라서 Resource Collector는 특정 핸들이나 포인터를 해제해도 괜찮은지를 알 수 없습니다.
편집 : .NET CLR과 관련하여 .NET 플랫폼을 사용한 C ++ 개발 경험이 없습니다. CLR이 관리 코드와 관리되지 않는 코드 사이의 핸들 / 포인터에 대한 참조를 추적 할 수 있도록하는 특별한 메커니즘이있을 수 있습니다. 이 경우 CLR은 해당 리소스의 수명을 관리하고 리소스에 대한 모든 참조가 지워지면 해제 할 수 있습니다 (적어도 일부 시나리오에서는 가능). 어느 쪽이든, 모범 사례는 핸들 (특히 파일을 가리키는 핸들)과 포인터가 필요하지 않은 즉시 해제되도록 지시합니다. Resource Collector는이를 준수하지 않을 것입니다. 이것이없는 이유입니다.
편집 2 : CLR / JVM / VM-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);