Objek tidak pernah keluar dari ruang lingkup di C # seperti yang mereka lakukan di C ++. Mereka ditangani oleh Pengumpul Sampah secara otomatis ketika mereka tidak digunakan lagi. Ini adalah pendekatan yang lebih rumit daripada C ++ di mana ruang lingkup variabel sepenuhnya deterministik. Pengumpul sampah CLR secara aktif menelusuri semua objek yang telah dibuat dan berfungsi jika sedang digunakan.
Objek bisa "keluar dari ruang lingkup" dalam satu fungsi tetapi jika nilainya dikembalikan, maka GC akan melihat apakah fungsi panggilan memegang nilai kembali.
Mengatur referensi objek null
tidak perlu karena pengumpulan sampah berfungsi dengan menentukan objek mana yang sedang direferensikan oleh objek lain.
Dalam praktiknya, Anda tidak perlu khawatir tentang kehancuran, itu hanya bekerja dan itu bagus :)
Dispose
harus dipanggil pada semua objek yang mengimplementasikan IDisposable
ketika Anda selesai bekerja dengannya. Biasanya Anda akan menggunakan using
blok dengan objek-objek seperti:
using (var ms = new MemoryStream()) {
//...
}
EDIT Pada lingkup variabel. Craig telah bertanya apakah ruang lingkup variabel memiliki efek pada masa hidup objek. Untuk menjelaskan dengan benar aspek CLR itu, saya perlu menjelaskan beberapa konsep dari C ++ dan C #.
Lingkup variabel aktual
Dalam kedua bahasa variabel hanya dapat digunakan dalam lingkup yang sama seperti yang didefinisikan - kelas, fungsi atau blok pernyataan terlampir oleh kurung kurawal. Perbedaan yang halus, bagaimanapun, adalah bahwa dalam C #, variabel tidak dapat didefinisikan ulang dalam blok bersarang.
Di C ++, ini sah menurut hukum:
int iVal = 8;
//iVal == 8
if (iVal == 8){
int iVal = 5;
//iVal == 5
}
//iVal == 8
Dalam C #, namun Anda mendapatkan kesalahan kompiler:
int iVal = 8;
if(iVal == 8) {
int iVal = 5; //error CS0136: A local variable named 'iVal' cannot be declared in this scope because it would give a different meaning to 'iVal', which is already used in a 'parent or current' scope to denote something else
}
Ini masuk akal jika Anda melihat MSIL yang dihasilkan - semua variabel yang digunakan oleh fungsi didefinisikan pada awal fungsi. Lihatlah fungsi ini:
public static void Scope() {
int iVal = 8;
if(iVal == 8) {
int iVal2 = 5;
}
}
Di bawah ini adalah IL yang dihasilkan. Perhatikan bahwa iVal2, yang didefinisikan di dalam blok if sebenarnya didefinisikan pada level fungsi. Secara efektif ini berarti bahwa C # hanya memiliki ruang lingkup tingkat kelas dan fungsi sejauh variabel yang bersangkutan.
.method public hidebysig static void Scope() cil managed
{
// Code size 19 (0x13)
.maxstack 2
.locals init ([0] int32 iVal,
[1] int32 iVal2,
[2] bool CS$4$0000)
//Function IL - omitted
} // end of method Test2::Scope
C ++ lingkup dan objek seumur hidup
Setiap kali variabel C ++, dialokasikan pada stack, keluar dari ruang lingkup itu akan hancur. Ingatlah bahwa di C ++ Anda dapat membuat objek di stack atau di heap. Ketika Anda membuatnya di stack, setelah eksekusi meninggalkan ruang lingkup, mereka akan muncul dari stack dan dihancurkan.
if (true) {
MyClass stackObj; //created on the stack
MyClass heapObj = new MyClass(); //created on the heap
obj.doSomething();
} //<-- stackObj is destroyed
//heapObj still lives
Ketika objek C ++ dibuat pada heap, mereka harus dihancurkan secara eksplisit, kalau tidak itu adalah kebocoran memori. Tidak ada masalah dengan variabel stack.
C # Obyek Seumur Hidup
Dalam CLR, objek (yaitu tipe referensi) selalu dibuat pada heap yang dikelola. Ini diperkuat oleh sintaks penciptaan objek. Pertimbangkan potongan kode ini.
MyClass stackObj;
Dalam C ++ ini akan membuat instance aktif MyClass
di stack dan memanggil konstruktor default-nya. Dalam C # itu akan membuat referensi ke kelas MyClass
yang tidak menunjuk ke apa pun. Satu-satunya cara untuk membuat instance kelas adalah dengan menggunakan new
operator:
MyClass stackObj = new MyClass();
Di satu sisi, objek C # sangat mirip objek yang dibuat menggunakan new
sintaks di C ++ - mereka dibuat di heap tetapi tidak seperti objek C ++, mereka dikelola oleh runtime, jadi Anda tidak perlu khawatir merusaknya.
Karena objek selalu di tumpukan fakta bahwa referensi objek (yaitu pointer) keluar dari ruang lingkup menjadi diperdebatkan. Ada lebih banyak faktor yang terlibat dalam menentukan apakah suatu objek harus dikumpulkan daripada sekadar kehadiran referensi ke objek.
C # Referensi objek
Jon Skeet membandingkan referensi objek di Jawa dengan potongan-potongan string yang melekat pada balon, yang merupakan objek. Analogi yang sama berlaku untuk referensi objek C #. Mereka hanya menunjuk ke lokasi tumpukan yang berisi objek. Dengan demikian, pengaturannya ke nol tidak memiliki efek langsung pada umur objek, balon terus ada, sampai GC "muncul" itu.
Melanjutkan analogi balon, akan tampak logis bahwa sekali balon tidak memiliki ikatan, balon itu dapat dihancurkan. Sebenarnya ini adalah persis bagaimana referensi menghitung objek bekerja dalam bahasa yang tidak dikelola Kecuali pendekatan ini tidak bekerja untuk referensi melingkar dengan sangat baik. Bayangkan dua balon yang disatukan oleh seutas tali tetapi tidak satu pun balon memiliki tali untuk yang lainnya. Di bawah aturan penghitungan ref sederhana, mereka berdua terus ada, meskipun seluruh kelompok balon "yatim piatu".
Objek NET sangat mirip balon helium di bawah atap. Ketika atap terbuka (GC run) - balon yang tidak digunakan melayang, meskipun mungkin ada kelompok balon yang ditambatkan bersama.
.NET GC menggunakan kombinasi GC generasi dan tanda serta sapuan. Pendekatan generasi melibatkan runtime yang mendukung untuk memeriksa objek yang telah dialokasikan terakhir, karena mereka lebih cenderung tidak digunakan dan menandai dan menyapu melibatkan runtime melalui seluruh grafik objek dan bekerja jika ada kelompok objek yang tidak digunakan. Ini cukup menangani masalah ketergantungan sirkuler.
Juga, .NET GC berjalan di utas lain (disebut utas finalizer) karena memiliki cukup banyak yang harus dilakukan dan melakukannya pada utas utama akan mengganggu program Anda.