垃圾收集器如何在这里避免无限循环?

时间:2014-07-09 19:42:23

标签: c# garbage-collection

考虑以下C#程序,我在codegolf上提交它作为创建循环而没有循环的答案:

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

这个程序在我的检查中看起来像一个无限循环,但似乎运行了几千次迭代,然后程序成功终止而没有错误(没有抛出错误)。是否违反了规范,P的终结器最终未被调用?

显然这是愚蠢的代码,应该永远不会出现,但我很好奇程序是如何完成的。

原码高尔夫球员:: https://codegolf.stackexchange.com/questions/33196/loop-without-looping/33218#33218

3 个答案:

答案 0 :(得分:110)

根据Richter在第二版CLR中通过C#(是的,我需要更新):

Page 478

  

对于(CLR正在关闭),每个 Finalize 方法大约需要两秒钟才能返回。如果 Finalize 方法在两秒内没有返回,则CLR会终止该进程 - 不再调用 Finalize 方法。此外,如果再次调用所有对象的 Finalize 方法需要40秒以上,CLR就会终止该过程。

此外,正如Servy所提到的,它有自己的主题。

答案 1 :(得分:23)

终结器不在主线程中运行。终结器有自己的运行代码的线程,它不是一个可以保持应用程序运行的前台线程。主线程立即有效地完成,此时终结器线程只是在进程被拆除之前运行多次。什么都没有让程序保持活力。

答案 2 :(得分:8)

垃圾收集器不是活动系统。它运行"有时"并且主要是按需(例如当操作系统提供的所有页面都已满)时。

大多数垃圾收集器在子线程中以类似广度的方式运行。在大多数情况下,物体回收可能需要数小时。

当您想要终止程序时,唯一的问题就出现了。然而,这不是一个真正的问题。当您使用kill时,操作系统会礼貌地要求终止进程。但是,当该过程保持活动状态时,可以使用操作系统删除所有控件的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并终止程序时。程序终止后五秒钟(换句话说,垃圾收集器放弃并简单地释放所有内存而不考虑终结器)。