GC berkaitan dengan sumber daya yang dapat diprediksi dan dicadangkan . VM memiliki kontrol total terhadapnya dan memiliki kontrol total atas instance apa yang dibuat dan kapan. Kata kunci di sini adalah "milik" dan "kontrol total". Pegangan dialokasikan oleh OS, dan pointer ... pointer juga ke sumber daya yang dialokasikan di luar ruang yang dikelola. Karena itu, pegangan dan pointer tidak terbatas untuk digunakan di dalam kode yang dikelola. Mereka dapat digunakan - dan seringkali - dengan kode yang dikelola dan tidak dikelola yang berjalan pada proses yang sama.
"Resource Collector" akan dapat memverifikasi apakah pegangan / penunjuk sedang digunakan dalam ruang yang dikelola atau tidak, tetapi menurut definisi tidak mengetahui apa yang terjadi di luar ruang memori itu (dan, untuk membuat keadaan lebih buruk beberapa pegangan dapat digunakan melintasi batas proses).
Contoh praktis adalah .NET CLR. Seseorang dapat menggunakan C ++ yang diberi aroma untuk menulis kode yang bekerja dengan ruang memori yang dikelola dan tidak dikelola; pegangan, penunjuk dan referensi dapat diedarkan antara kode yang dikelola dan tidak dikelola. Kode yang tidak dikelola harus menggunakan konstruksi / tipe khusus untuk memungkinkan CLR untuk terus melacak referensi yang dibuat untuk sumber daya yang dikelola itu. Tapi itu yang terbaik yang bisa dilakukan. Ia tidak dapat melakukan hal yang sama dengan handle dan pointer, dan karena itu Resource Collector tidak akan tahu apakah boleh melepaskan handel atau pointer tertentu.
sunting: Mengenai. NET CLR, saya tidak berpengalaman dengan pengembangan C ++ dengan platform .NET. Mungkin ada mekanisme khusus di tempat yang memungkinkan CLR untuk terus melacak referensi untuk menangani / petunjuk antara kode yang dikelola dan tidak dikelola. Jika itu yang terjadi maka CLR dapat mengurus masa pakai sumber daya tersebut dan melepaskannya ketika semua referensi tentangnya telah dihapus (yah, setidaknya dalam beberapa skenario hal itu bisa). Either way, praktik terbaik menentukan yang menangani (terutama yang menunjuk ke file) dan pointer harus dirilis segera setelah mereka tidak diperlukan. Seorang Resource Collector tidak akan menaatinya, itu alasan lain untuk tidak memilikinya.
sunting 2: Ini relatif sepele pada CLR / JVM / VMs-in-general untuk menulis beberapa kode untuk membebaskan pegangan tertentu jika hanya digunakan di dalam ruang yang dikelola. Dalam. NET akan menjadi sesuatu seperti:
// 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);
Ada banyak teknik pemrograman untuk membantu mengelola sumber daya semacam ini.
Pemrogram C ++ sering menggunakan pola yang disebut Resource Acquisition is Inisialisasi , atau singkatnya RAII. Pola ini memastikan bahwa ketika suatu benda yang memegang sumber daya keluar dari ruang lingkup, itu akan menutup sumber daya yang dipegangnya. Ini membantu ketika masa hidup objek sesuai dengan cakupan tertentu dalam program (misalnya, ketika cocok dengan waktu ketika bingkai tumpukan tertentu hadir pada tumpukan), sehingga sangat membantu untuk objek yang ditunjuk oleh variabel lokal (pointer variabel disimpan di stack), tetapi tidak begitu membantu untuk objek yang ditunjuk oleh pointer yang disimpan di heap.
Java, C #, dan banyak bahasa lainnya menyediakan cara untuk menentukan metode yang akan dipanggil ketika sebuah objek tidak lagi hidup dan akan dikumpulkan oleh pengumpul sampah. Lihat, misalnya, finalizer
dispose()
,, dan lainnya. Idenya adalah bahwa pemrogram dapat menerapkan metode seperti itu sehingga akan secara eksplisit menutup sumber daya sebelum objek dibebaskan oleh pengumpul sampah. Namun, pendekatan ini memiliki beberapa masalah, yang dapat Anda baca di tempat lain; misalnya, pengumpul sampah mungkin tidak mengumpulkan objek sampai jauh lebih lama dari yang Anda inginkan.C # dan bahasa lainnya menyediakan
using
kata kunci yang membantu memastikan bahwa sumber daya ditutup setelah tidak lagi diperlukan (jadi Anda jangan lupa untuk menutup file descriptor atau sumber daya lainnya). Ini seringkali lebih baik daripada mengandalkan pengumpul sampah untuk menemukan bahwa objek tidak lagi hidup. Lihat, misalnya, /programming//q/75401/781723 . Istilah umum di sini adalah sumber daya yang dikelola . Gagasan ini dibangun di atas RAII dan penyelesai, meningkatkannya dengan beberapa cara.sumber
Semua memori sama, jika saya meminta 1K, saya tidak peduli dari mana di ruang alamat 1K berasal.
Ketika saya meminta pegangan file, saya ingin pegangan ke file yang ingin saya buka. Memiliki pegangan file yang terbuka pada file, sering memblokir akses ke file oleh proses lain, atau mesin.
Karenanya pegangan file harus ditutup segera setelah tidak diperlukan, jika tidak mereka memblokir akses lain ke file tersebut, tetapi memori hanya perlu direklamasi ketika Anda mulai kehabisan.
Menjalankan pass GC mahal dan hanya dilakukan "bila diperlukan", tidak mungkin untuk memprediksi kapan proses anther akan membutuhkan file menangani bahwa proses Anda mungkin tidak lagi menggunakan, tetapi masih terbuka.
sumber
Saya akan menebak alasan mengapa ini belum banyak didekati untuk sumber daya lain adalah karena sebagian besar sumber daya lain lebih disukai untuk dirilis sesegera mungkin bagi siapa saja untuk digunakan kembali.
Catatan, tentu saja, contoh Anda dapat diberikan sekarang menggunakan deskriptor file "lemah" dengan teknik GC yang ada.
sumber
Untuk memeriksa apakah memori tidak lagi dapat diakses (dan dengan demikian dijamin tidak akan digunakan lagi) agak mudah. Sebagian besar jenis sumber daya lainnya dapat ditangani dengan teknik yang kurang lebih sama (yaitu, akuisisi sumber daya adalah inisialisasi, RAII, dan mitra pembebasannya ketika pengguna dimusnahkan, yang menghubungkannya dengan administrasi memori). Melakukan semacam pembebasan "tepat waktu" tidak mungkin secara umum (periksa masalah penghentian, Anda harus mengetahui bahwa beberapa sumber daya digunakan untuk yang terakhir kalinya). Ya, kadang - kadang dapat dilakukan secara otomatis, tetapi ini merupakan kasus yang jauh lebih berantakan daripada memori. Jadi itu bergantung pada intervensi pengguna untuk sebagian besar.
sumber