GC.Collect () [duplicate] sonrasında sonlandırıcı çağrılmadı
Sanırım temel bir şeyi kaçırıyorum ve yardım edebileceğinizi umuyorum. Aşağıdaki kod bir nesne oluşturur, referansı kaldırır ve çöp toplayıcıyı çağırır. Benim beklentim, Readline'da dururken SomeClass'ın sonlandırıcısının çağrılmasıydı. Öyle değil. Bir döngüde GC.Collect'i çağırmayı denedim, sonlandırıcı iş parçacığının başlatılması için bazı Sleep () çağrıları ekledim. Gerçekleşmez.
Sadece Main sona erdiğinde finalizer vurulur, ancak şaşırtıcı bir şekilde iki kez vurulur. Neyi kaçırıyorum?
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();
}
}
Eklenti Bir programı hata ayıklama modunda çalıştırma ile yayınlama modu arasında bir fark vardır. Aşağıdaki program hata ayıklama modunda Start - Done - Finalize
üretirken yayınlama modunda günlük dosyası gösterir Start - Finalize - Done
. İkincisi beklediğim gibi.
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");
}
}
Yanıtlar
Çöp toplanan nesneler sonlandırmaya uygun hale gelir ve bir sonlandırma kuyruğuna alınır. Bu sonlandırıcıların çalışacağına dair kesinlikle hiçbir garanti yok .
Sizi Eric Lippert'in bu konuyla ilgili olarak "Bildiğiniz her şey yanlış olduğunda" adı verilen harika yazılara yönlendireceğim . Özellikle:
Efsane: Bir değişkeni null olarak ayarlamak, sonlandırıcının daha önce değişken tarafından başvurulan nesne üzerinde çalışmasına neden olur. Bir değişkeni null olarak ayarlamak, değişkenin değerini değiştirmek dışında hemen hiçbir şeyin olmasına neden olmaz. Değişken, söz konusu nesneye son canlı referans ise, bu gerçek, çöp toplayıcı, nesnenin içinde bulunduğu nesil için toplayıcıyı çalıştırdığında keşfedilecektir. (Çalışıyorsa, çalışmayabilir. Garanti yoktur. GC çalışır.)
Ve hatta GC.Collect()
:
Efsane: Çağrı
GC.Collect()
, sonuçlandırıcıların çalışmasına neden olur. Hayır, bir koleksiyon oluşmasına neden olur. Bu, sonlandırma için aday olan nesneleri tanımlayabilir, ancak sonlandırıcı iş parçacığını planlanmaya zorlamaz. İstediğiniz buysa - sadece test amaçlı lütfen! - sonra araGC.WaitForPendingFinalizers()
.
Yani en iyi başarı şansı ile GC.WaitForPendingFinalizers()
. Ancak o zaman bile, sizi gönderinin geri kalanına ( ve devamına ) atıfta bulunarak , SONLANDIRICILARIN ÇALIŞMA GARANTİSİ DEĞİLDİR . Buna güvenme.
Bu soru hakkında daha ayrıntılı bir açıklama yazdım, böylece bunu daha fazla araştırma yapmak için bir başlangıç noktası olarak kullanabilirsiniz.