Bir çöp toplayıcı burada sonsuz döngüden nasıl kaçınır?


101

Aşağıdaki C # programını düşünün, döngüsüz bir döngü oluşturmak için bir cevap olarak kod golfüne gönderdim:

class P{
    static int x=0;
    ~P(){
        System.Console.WriteLine(++x);
        new P();
    }
    static void Main(){
        new P();
    }
}

Bu program, incelememde sonsuz bir döngü gibi görünüyor, ancak birkaç bin yineleme için çalışıyor gibi görünüyor ve sonra program hatasız başarıyla sona eriyor (Hata atılmıyor). PSonunda sonuçlandırıcının çağrılmaması bir şartname ihlali mi?

Açıkçası bu aptalca bir kod, asla görünmemesi gerekiyor, ancak programın nasıl tamamlanacağını merak ediyorum.

Orijinal kod golf yayını :: /codegolf/33196/loop-without-looping/33218#33218


49
Bunu çalıştırmaktan korkuyorum.
Eric Scherrer

6
Bir sonlandırıcının çağrılmaması kesinlikle geçerli davranış alanı içindedir . Yine de birkaç bin yineleme çalıştırmanın neden rahatsız olduğunu bilmiyorum, sıfır çağrı bekliyorum.

27
CLR, sonlandırıcı ipliğin işini asla bitirememesine karşı korumaya sahiptir. 2 saniye sonra zorla sonlandırır.
Hans Passant

2
Yani başlıktaki sorunuzun gerçek cevabı, sonsuz döngünün 40 saniye çalışmasına izin vererek bundan kaçınması ve sonra sonlandırılmasıdır.
Lasse V.Karlsen

4
Denemekten, program ne olursa olsun 2 saniye sonra her şeyi öldürüyor gibi görünüyor. Aslında, dizileri üretmeye devam ederseniz, biraz daha uzun sürecek :)
Michael B

Yanıtlar:


110

Richter'e göre CLR'nin C # aracılığıyla ikinci sürümünde (evet güncellemem gerekiyor):

Sayfa 478

(CLR kapatılıyor) için her Finalize yöntemine geri dönmesi için yaklaşık iki saniye verilir. Bir Finalize yöntemi iki saniye içinde geri dönmezse, CLR yalnızca işlemi sonlandırır - artık Finalize yöntemi çağrılmaz. Ayrıca, tüm nesnelerin Finalize yöntemlerini çağırmak 40 saniyeden fazla sürerse , yine CLR işlemi sonlandırır.

Ayrıca, Servy'nin de belirttiği gibi, kendi iş parçacığı vardır.


5
Bu koddaki her bir sonlandırma yöntemi, nesne başına önemli ölçüde 40 saniyenin altında sürer. Yeni bir nesnenin yaratılması ve ardından sonlandırmaya uygun olması, mevcut sonlandırıcıyla ilgili değildir.
Jacob Krall

2
Aslında işi yapan şey bu değil. Kapatma sırasında serbest bırakılabilir kuyrukta boşalan bir zaman aşımı da var. Bu kodun başarısız olduğu şey bu, kuyruğa yeni nesneler eklemeye devam ediyor.
Hans Passant

Sadece bunu düşünmek, freachable kuyruğunu "Ayrıca, tüm nesnelerin Sonlandırma yöntemlerini çağırmak 40 saniyeden fazla sürerse, yine CLR işlemi sonlandırır."
Eric Scherrer

23

Sonlandırıcı ana iş parçacığında çalışmıyor. Sonlandırıcının, kodu çalıştıran kendi iş parçacığı vardır ve bu, uygulamanın çalışmasını sağlayacak bir ön plan iş parçacığı değildir. Ana iş parçacığı hemen etkili bir şekilde tamamlanır, bu noktada sonlandırıcı iş parçacığı, işlem bozulmadan önce bir şans elde ettiği kadar çok çalışır. Hiçbir şey programı canlı tutmuyor.


Sonlandırıcı, ana iş parçacığının canlı olmaması nedeniyle programdan çıkılmasından 40 saniye sonra tamamlanmadıysa, sonlandırılacak ve işlem sona erecektir. Bunlar eski değerlerdir, bu yüzden Microsoft şimdiye kadar gerçek sayıları ve hatta tüm algoritmayı değiştirmiş olabilir. Se blog.stephencleary.com/2009/08/finalizers-at-process-exit.html
Lasse V. Karlsen

@ LasseV.Karlsen Dilin bu şekilde belgelenmiş davranışı mı, yoksa MS sonlandırıcılarını bir uygulama ayrıntısı olarak nasıl uygulamayı seçti? İkincisini beklerdim.
14'te

İkincisini de bekliyorum. Gördüğüm bu davranışa en resmi referans, Eric'in, Jeffrey Richter'in C # aracılığıyla CLR kitabından cevabında yazdığı şeydir.
Lasse V. Karlsen

8

Çöp toplayıcı, aktif bir sistem değildir. "Bazen" ve çoğunlukla talep üzerine çalışır (örneğin, işletim sistemi tarafından sunulan tüm sayfalar dolu olduğunda).

Çoğu çöp toplayıcı, bir alt iş parçacığında enine birinci nesil benzeri bir şekilde çalışır. Çoğu durumda nesnenin geri dönüştürülmesi saatler sürebilir.

Tek sorun, programı sonlandırmak istediğinizde ortaya çıkar. Ancak bu gerçekten bir sorun değil. Bir killişletim sistemi kullandığınızda kibarca süreçleri sonlandırmanızı isteyecektir. Ancak süreç aktif kaldığında kill -9, İşletim Sisteminin tüm kontrolü kaldırdığı yerde kullanılabilir .

Kodunuzu etkileşimli csharportamda çalıştırdığımda, elimde:

csharp>  

1
2

Unhandled Exception:
System.NotSupportedException: Stream does not support writing
  at System.IO.FileStream.Write (System.Byte[] array, Int32 offset, Int32 count) [0x00000] in <filename unknown>:0 
  at System.IO.StreamWriter.FlushBytes () [0x00000] in <filename unknown>:0 
  at System.IO.StreamWriter.FlushCore () [0x00000] in <filename unknown>:0 
  at System.IO.StreamWriter.Write (System.Char[] buffer, Int32 index, Int32 count) [0x00000] in <filename unknown>:0 
  at System.IO.CStreamWriter.Write (System.Char[] buffer, Int32 index, Int32 count) [0x00000] in <filename unknown>:0 
  at System.IO.CStreamWriter.Write (System.Char[] val) [0x00000] in <filename unknown>:0 
  at System.IO.CStreamWriter.Write (System.String val) [0x00000] in <filename unknown>:0 
  at System.IO.TextWriter.Write (Int32 value) [0x00000] in <filename unknown>:0 
  at System.IO.TextWriter.WriteLine (Int32 value) [0x00000] in <filename unknown>:0 
  at System.IO.SynchronizedWriter.WriteLine (Int32 value) [0x00000] in <filename unknown>:0 
  at System.Console.WriteLine (Int32 value) [0x00000] in <filename unknown>:0 
  at P.Finalize () [0x00000] in <filename unknown>:0

Böylece programınız stdout, ortamın sona ermesiyle engellendiği için çöker .

Console.WriteLineProgramı kaldırırken ve sonlandırırken. Beş saniye sonra program sona erer (başka bir deyişle, çöp toplayıcı vazgeçer ve sonlandırıcıları hesaba katmadan tüm belleği serbest bırakır).


Etkileşimli csharp'ın tamamen farklı nedenlerden dolayı patlaması büyüleyici. Orijinal program parçacığı konsol yazıcısına sahip değildi, ben de sona erer mi merak ediyorum.
Michael B

@MichaelB: Bunu da test ettim (aşağıdaki yoruma bakın). Beş saniye bekler ve sonra sona erer. Sanırım ilk Pörneğin sonlandırıcısı zaman aşımına uğradı.
Willem Van Onsem
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.