GC เกี่ยวข้องกับทรัพยากรที่สามารถคาดการณ์ได้และสงวนไว้ VM มีการควบคุมทั้งหมดและมีการควบคุมทั้งหมดว่าจะสร้างอินสแตนซ์ใดและเมื่อใด คำหลักที่นี่คือ "ลิขสิทธิ์" และ "การควบคุมทั้งหมด" หมายเลขอ้างอิงถูกจัดสรรโดยระบบปฏิบัติการและตัวชี้คือ ... ตัวชี้ที่ดีสำหรับทรัพยากรที่จัดสรรนอกพื้นที่ที่ได้รับการจัดการ เนื่องจากการจับและพอยน์เตอร์จึงไม่ถูก จำกัด ให้ใช้ภายในรหัสที่ได้รับการจัดการ พวกเขาสามารถใช้ - และมักจะ - โดยการจัดการและไม่มีการจัดการรหัสที่ทำงานในกระบวนการเดียวกัน
"ตัวสะสมทรัพยากร" จะสามารถตรวจสอบได้ว่ามีการใช้ตัวจัดการ / ตัวชี้ภายในพื้นที่ที่มีการจัดการหรือไม่ แต่โดยนิยามแล้วไม่ทราบว่าเกิดอะไรขึ้นนอกพื้นที่หน่วยความจำ (และเพื่อทำให้สิ่งเลวร้ายยิ่งขึ้น ข้ามขอบเขตกระบวนการ)
ตัวอย่างการปฏิบัติคือ. NET CLR หนึ่งสามารถใช้ C ++ ปรุงแต่งเพื่อเขียนรหัสซึ่งทำงานกับพื้นที่หน่วยความจำที่มีการจัดการและไม่มีการจัดการ จับพอยน์เตอร์และการอ้างอิงสามารถส่งผ่านระหว่างรหัสที่มีการจัดการและไม่มีการจัดการ รหัสที่ไม่มีการจัดการต้องใช้โครงสร้าง / ประเภทพิเศษเพื่ออนุญาตให้ CLR ติดตามการอ้างอิงที่ทำกับทรัพยากรที่มีการจัดการ แต่นั่นเป็นสิ่งที่ดีที่สุดที่จะทำได้ ไม่สามารถทำเช่นเดียวกันกับที่จับและพอยน์เตอร์และเนื่องจากที่กล่าวว่า Resource Collector จะไม่ทราบว่ามันโอเคที่จะปล่อยหมายเลขอ้างอิงหรือตัวชี้เฉพาะ
แก้ไข: เกี่ยวกับ. NET CLR ฉันไม่ได้มีประสบการณ์กับการพัฒนา C ++ กับแพลตฟอร์ม. NET อาจมีกลไกพิเศษที่ช่วยให้ CLR ติดตามการอ้างอิงไปยังหมายเลขอ้างอิง / ตัวชี้ระหว่างรหัสที่ได้รับการจัดการและไม่มีการจัดการ หากเป็นเช่นนั้น CLR สามารถดูแลอายุการใช้งานของทรัพยากรเหล่านั้นและปล่อยเมื่อมีการเคลียร์การอ้างอิงถึงพวกเขาทั้งหมด (อย่างน้อยในบางสถานการณ์ก็ทำได้) ทั้งสองวิธีแนวปฏิบัติที่ดีที่สุดกำหนดว่าจัดการ (โดยเฉพาะอย่างยิ่งที่ชี้ไปที่ไฟล์) และพอยน์เตอร์ควรได้รับการปล่อยตัวทันทีที่ไม่จำเป็น ตัวรวบรวมทรัพยากรจะไม่ปฏิบัติตามสิ่งนั้นนั่นเป็นอีกสาเหตุหนึ่งที่ไม่มี
แก้ไข 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);