C#中在类的析构函数中使用new()的效果探究
析构函数中创建实例未引发StackOverflowException反而终止的原因分析
我做了个学术实验,想搞明白为什么程序会正常终止,而不是抛出StackOverflowException。我只在类的析构函数/终结器里创建新实例,原本以为代码会像while(true)循环一样永久运行。相关代码和运行输出如下:
实验代码
class Animal { static int i = 0; public Animal() { Animal.i = Animal.i + 1; Console.WriteLine(i + " Object created.." ); } ~Animal() { new Animal(); } } internal class Program { static void Main(string[] args) { Animal a = new Animal(); } }
运行输出示例
运行1输出:
76727 Object created.. 76728 Object created.. 76729 Object created.. Press any key to continue . . .
运行2输出:
76818 Object created.. 76819 Object created.. 76820 Object created.. 76821 Object created.. Press any key to continue . . .
原因解析
这背后是.NET垃圾回收(GC)和终结器队列的工作机制在起作用:
- 当
Main方法执行完毕,第一个Animal实例失去引用,被GC标记为可回收。 - GC处理该实例时,会将它的终结器放入终结器队列,由专门的终结器线程执行。
- 终结器线程执行
~Animal()时创建新的Animal实例,这个新实例后续也会被GC处理并触发终结器,看似形成循环,但实际有几个关键限制:- .NET的终结器线程执行受GC调度,CLR会限制终结器的执行次数,避免无限循环耗尽系统资源。当内存使用达到阈值,GC会调整策略,不再继续处理新的终结器请求。
- 主线程已经结束(
Main执行完成),GC在后台处理终结器,但当没有更多根引用,且终结器队列的处理达到一定限度后,CLR会直接终止程序,不会让循环无限进行。
- 这和
while(true)这种在主线程的同步循环完全不同,终结器执行在后台线程,受CLR资源管理策略约束,所以不会无限运行,最终程序正常终止。
内容的提问来源于stack exchange,提问作者Sekhar
相关产品推荐
相关产品推荐

