ガベージコレクターは、ここで無限ループをどのように回避しますか?


101

次のC#プログラムについて考えてみましょう。ループなしのループを作成するための回答としてcodegolfに提出しました。

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

このプログラムは、私の検査では無限ループのように見えますが、数千回繰り返し実行されているように見え、プログラムはエラーなしで正常に終了します(エラーはスローされません)。P最終的にファイナライザが呼び出されないのは仕様違反ですか?

明らかにこれは馬鹿げたコードであり、決して表示されるべきではありませんが、プログラムがどのように完了するかについて私は興味があります。

オリジナルコードゴルフポスト:: /codegolf/33196/loop-without-looping/33218#33218


49
これを実行するのは怖いです。
Eric Sc​​herrer、2014

6
ファイナライザが呼び出されないことは、確かに有効な動作の範囲内です。なぜ数千回の反復を実行するのが面倒なのかはわかりませんが、呼び出しがゼロになると予想します。

27
CLRには、ファイナライザスレッドがそのジョブを完了できないことに対する保護があります。2秒後に強制終了します。
ハンスパッサント2014

2
したがって、タイトルの質問に対する本当の答えは、無限ループを40秒間実行するだけで回避でき、その後終了するということです。
Lasse V. Karlsen、2014

4
試してみると、プログラムは何があっても2秒後にすべてを強制終了するようです。実際にスレッドをスポーンし続けると、それはかなり長く続きます:)
Michael B

回答:


110

C#を介したCLRの第2版のリヒターによると(はい、更新する必要があります):

さちえ478

(CLRのシャットダウン中)の場合、各Finalizeメソッドには約2秒かかります。Finalizeメソッドが2秒以内に返らない場合、CLRはプロセスを強制終了するだけで、Finalizeメソッドは呼び出されません。また、すべてのオブジェクトのFinalizeメソッドの呼び出しに40秒以上かかる場合も、CLRはプロセスを強制終了します。

また、Servyが言及するように、独自のスレッドがあります。


5
このコードの各finalizeメソッドは、オブジェクトごとに40秒未満の劇的な時間がかかります。新しいオブジェクトが作成され、ファイナライズに適格であることは、現在のファイナライザには関係ありません。
Jacob Krall 2014

2
これは実際には仕事を成し遂げるものではありません。シャットダウン時に空になるフリーチ可能なキューにもタイムアウトがあります。これはこのコードが失敗したものであり、新しいオブジェクトをそのキューに追加し続けます。
ハンスパッサント2014

これについて考えるだけでは、「すべてのオブジェクトのFinalizeメソッドを呼び出すのに40秒以上かかる場合も、CLRがプロセスを強制終了するだけです」と同じように、feachableキューを空にするのではありません。
エリックシェラー2014

23

ファイナライザはメインスレッドでは実行されません。ファイナライザには、コードを実行する独自のスレッドがあり、アプリケーションを実行し続けるフォアグラウンドスレッドではありません。メインスレッドはすぐに効果的に完了します。この時点で、ファイナライザスレッドは、プロセスが破棄される前に、機会が得られる回数だけ実行されます。プログラムを存続させるものは何もない。


メインスレッドが存在しないためにプログラムが終了してから40秒後にファイナライザが完了しなかった場合、ファイナライザは終了し、プロセスが終了します。これらは古い値ですが、Microsoftは現在までに実際の数値またはアルゴリズム全体を微調整した可能性があります。Se blog.stephencleary.com/2009/08/finalizers-at-process-exit.html
Lasse V. Karlsen 14

@ LasseV.Karlsenその文書化された言語の動作ですか、それとも単にMSが実装の詳細としてファイナライザを実装することを選択したのですか?私は後者を期待します。
サービー2014

後者も期待しています。私が見たこの動作への最も公式な言及は、Jeffrey RichterによるC#を介したCLRの本から、エリックが彼の回答で投稿したものです。
Lasse V. Karlsen、2014

8

ガベージコレクターはアクティブなシステムではありません。「時々」、ほとんどがオンデマンドで実行されます(たとえば、OSによって提供されるすべてのページがいっぱいになった場合)。

ほとんどのガベージコレクターは、サブスレッドで幅第一世代のような方法で実行されます。ほとんどの場合、オブジェクトがリサイクルされるまでに数時間かかることがあります。

唯一の問題は、プログラムを終了するときに発生します。しかし、それは本当に問題ではありません。あなたkillがOS を使用するとき、プロセスを終了するように丁寧に尋ねます。ただし、プロセスがアクティブのままkill -9である場合は、オペレーティングシステムがすべての制御を削除する場所を使用できます。

インタラクティブcsharp環境でコードを実行したとき、次のことがわかりました。

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

したがってstdout、環境の終了によってブロックされるため、プログラムがクラッシュします。

を削除Console.WriteLineしてプログラムを強制終了する場合。5秒後にプログラムが終了します(つまり、ガベージコレクターはあきらめ、ファイナライザーを考慮せずにすべてのメモリを解放します)。


これは、インタラクティブなcsharpがまったく異なる理由で爆発するのが魅力的です。元のプログラムスニペットにはコンソールの書き込みラインがありませんでしたが、終了するかどうか知りたいです。
マイケルB

@MichaelB:私もこれをテストしました(以下のコメントを参照)。5秒間待機してから終了します。最初のPインスタンスのファイナライザが単にタイムアウトしたと思います。
Willem Van Onsem 14
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.