为何以下C#代码中的析构函数始终未被调用?
为什么C#中析构函数从未被调用?
我原本以为当类实例超出作用域且垃圾回收器执行回收时,析构函数会被调用,但下面的代码里析构函数从来没被触发,这是怎么回事?
while (true) { var Thing1 = new Thing(); await Task.Delay(100); } class Thing { ~Thing() { Console.WriteLine("Destructed"); } }
这事儿我太清楚了!咱们来掰扯清楚原因:
- GC不是即时响应的:C#的垃圾回收器不会在对象刚离开作用域就立刻启动回收。你的循环每次创建的
Thing实例体积极小,内存占用一直没达到GC的触发阈值,所以GC根本没机会跑,析构函数自然不会执行。 - 终结器的执行有延迟:就算GC真的启动了,析构函数(也就是终结器)也不是立刻执行的——它会被放到终结队列里,等专门的终结线程来处理。而你的无限循环一直占着主线程,可能连GC的正常回收周期都被打乱了。
如果想验证析构函数确实能工作,可以试试这两个方法:
- 手动强制GC:在循环里加入
GC.Collect(); GC.WaitForPendingFinalizers();,强制GC回收并等待所有终结器执行,你就能看到"Destructed"的输出了:while (true) { var Thing1 = new Thing(); await Task.Delay(100); GC.Collect(); GC.WaitForPendingFinalizers(); } class Thing { ~Thing() { Console.WriteLine("Destructed"); } } - 增大内存压力:给
Thing类加一个大内存的成员,比如byte[] largeBuffer = new byte[1024 * 1024];,这样每次创建实例都会占用1MB内存,很快就会触发GC自动回收。
最后提个醒:实际开发里别随便手动调用GC,这只是调试验证的手段。终结器本身也尽量少用,它会增加GC的工作负担,优先用IDisposable模式来管理非托管资源才是更靠谱的做法。
内容的提问来源于stack exchange,提问作者manidos
相关产品推荐
相关产品推荐

