Saya memiliki kelas sederhana yang didefinisikan seperti di bawah ini.
public class Person
{
public Person()
{
}
public override string ToString()
{
return "I Still Exist!";
}
~Person()
{
p = this;
}
public static Person p;
}
Dalam metode Utama
public static void Main(string[] args)
{
var x = new Person();
x = null;
GC.Collect();
GC.WaitForPendingFinalizers();
Console.WriteLine(Person.p == null);
}
Apakah pengumpul sampah seharusnya menjadi referensi utama untuk Person.p dan kapan tepatnya destructor dipanggil?
c#
.net
garbage-collection
Parimal Raj
sumber
sumber
Person1
? Saya hanya melihatPerson
. Terakhir: lihat docs.microsoft.com/dotnet/csharp/programming-guide/… untuk cara kerja finalizers.Person1
sebenarnyaPerson
, memperbaiki kesalahan ketik.GC.Collect
panggilanJawaban:
Hal yang Anda lewatkan di sini adalah bahwa kompiler memperpanjang masa hidup
x
variabel Anda sampai akhir metode di mana ia didefinisikan - itu hanya sesuatu yang dikompilasi - tetapi hanya melakukannya untuk membangun DEBUG.Jika Anda mengubah kode sehingga variabel didefinisikan dalam metode terpisah, itu akan berfungsi seperti yang Anda harapkan.
Output dari kode berikut adalah:
Dan kodenya:
Jadi pada dasarnya pemahaman Anda benar, tetapi Anda tidak tahu bahwa kompiler licik akan membuat variabel Anda tetap hidup sampai setelah Anda menelepon
GC.Collect()
- bahkan jika Anda secara eksplisit mengaturnya ke nol!Seperti yang saya sebutkan di atas, ini hanya terjadi untuk build DEBUG - mungkin sehingga Anda dapat memeriksa nilai-nilai untuk variabel lokal saat debugging ke akhir metode (tapi itu hanya dugaan!).
Kode asli TIDAK berfungsi seperti yang diharapkan untuk rilis build - jadi kode berikut ini menghasilkan
false, true
untuk build RELEASE danfalse, false
untuk build DEBUG:Sebagai tambahan: Perhatikan bahwa jika Anda melakukan sesuatu di finalizer untuk kelas yang menyebabkan referensi ke objek yang difinalisasi dapat dijangkau dari root program, maka objek itu TIDAK akan menjadi pengumpulan sampah kecuali dan sampai objek itu tidak lagi direferensikan.
Dengan kata lain, Anda dapat memberikan objek "penundaan eksekusi" melalui finalizer. Ini umumnya dianggap sebagai desain yang buruk!
Misalnya, dalam kode di atas, di mana kita melakukannya
_extendMyLifetime = this
di finalizer, kita sedang membuat referensi baru ke objek, jadi sekarang tidak akan dikumpulkan sampah sampai_extendMyLifetime
(dan referensi lainnya) tidak lagi referensi itu.sumber