finalizer tidak dipanggil setelah GC.Collect () [duplikat]
Saya rasa saya kehilangan sesuatu yang mendasar dan berharap Anda dapat membantu. Kode di bawah ini membuat sebuah objek, menghapus referensi dan memanggil pengumpul sampah. Harapan saya adalah finalizer SomeClass akan dipanggil saat berdiri di Readline. Tidak. Saya sudah mencoba memanggil GC.Collect dalam satu lingkaran, menambahkan beberapa panggilan Sleep () agar utas finalizer dimulai. Tidak terjadi.
Hanya ketika Main berakhir finalizer dipukul, tetapi yang mengejutkan dipukul dua kali. Apa yang saya lewatkan?
class Program
{
public static void Main(string[] args)
{
SomeClass some = new SomeClass("Hello World!");
some = null;
GC.Collect();
GC.WaitForPendingFinalizers();
Console.WriteLine("Done");
Console.ReadLine();
}
}
class SomeClass
{
string ss;
public SomeClass(string s) { ss = s; }
~SomeClass()
{
var hash = this.GetHashCode();
}
}
Adendum Ada perbedaan dalam menjalankan program dalam mode debug versus mode rilis. Program di bawah ini menghasilkan mode debug Start - Done - Finalize
sedangkan dalam mode rilis logfile ditampilkan Start - Finalize - Done
. Yang terakhir adalah yang saya harapkan.
class Program
{
private static string logfile = @"c:\temp\log.txt";
public static void Main(string[] args)
{
File.WriteAllText(logfile, "Start\n");
SomeClass some = new SomeClass("Hello World!");
some = null;
GC.Collect();
GC.WaitForPendingFinalizers();
File.AppendAllText(logfile, "Done\n");
}
}
class SomeClass
{
private static string logfile = @"c:\temp\log.txt";
public string SomeString { get; set; }
public SomeClass(string s) { SomeString = s; }
~SomeClass()
{
File.AppendAllText(logfile, "Finalize\n");
}
}
Jawaban
Objek yang sampah dikumpulkan menjadi cocok untuk finalisasi dan ditempatkan pada antrian finalisasi. Sama sekali tidak ada jaminan bahwa finalisator tersebut akan terus berjalan .
Saya akan mengarahkan Anda ke postingan bagus dari Eric Lippert tentang ini, yang secara tepat disebut "Ketika semua yang Anda ketahui salah." Khususnya:
Mitos: Menetapkan variabel ke nol menyebabkan finalizer berjalan pada objek yang sebelumnya direferensikan oleh variabel. Menetapkan variabel ke nol tidak menyebabkan apa pun terjadi dengan segera kecuali mengubah nilai variabel. Jika variabel adalah referensi hidup terakhir ke objek yang dipermasalahkan, maka fakta itu akan ditemukan saat pengumpul sampah menjalankan pengumpul untuk generasi apa pun tempat objek itu berada. (Jika berjalan sama sekali, yang mungkin tidak akan terjadi. Tidak ada jaminan yang dijalankan GC.)
Dan bahkan dengan GC.Collect()
:
Mitos: Memanggil
GC.Collect()
menyebabkan finalizer berjalan. Tidak, itu menyebabkan pengumpulan terjadi. Itu mungkin mengidentifikasi objek yang merupakan kandidat untuk finalisasi, tetapi itu tidak memaksa utas finalizer untuk dijadwalkan. Jika itu yang Anda inginkan - untuk tujuan pengujian saja! - lalu teleponGC.WaitForPendingFinalizers()
.
Jadi peluang sukses terbaik adalah bersama GC.WaitForPendingFinalizers()
. Tetapi meskipun demikian, merujuk Anda ke sisa pos ( dan sekuelnya ), FINALIZER TIDAK DIJAMIN UNTUK BERLARI . Jangan tergantung itu.
Penjelasan yang lebih rinci tentang pertanyaan ini saya tulis agar Anda dapat menggunakannya sebagai titik awal untuk penelitian lebih lanjut.