提问人:fluter 提问时间:6/24/2017 最后编辑:Peter Dunihofluter 更新时间:8/16/2018 访问量:5966
为什么 Finalize/Destructor 示例在 .NET Core 中不起作用?
Why does the Finalize/Destructor example not work in .NET Core?
问:
我正在尝试了解终结和析构函数在 C# 中的工作原理,我尝试运行 System.Object.Finalize
示例中的代码(代码复制粘贴,未进行任何更改),但输出与预期不同,它显示析构函数从未被调用。
代码为:
using System;
using System.Diagnostics;
public class ExampleClass
{
Stopwatch sw;
public ExampleClass()
{
sw = Stopwatch.StartNew();
Console.WriteLine("Instantiated object");
}
public void ShowDuration()
{
Console.WriteLine("This instance of {0} has been in existence for {1}",
this, sw.Elapsed);
}
~ExampleClass()
{
Console.WriteLine("Finalizing object");
sw.Stop();
Console.WriteLine("This instance of {0} has been in existence for {1}",
this, sw.Elapsed);
}
}
public class Demo
{
public static void Main()
{
ExampleClass ex = new ExampleClass();
ex.ShowDuration();
}
}
更新:
当我使用 Visual Studio 和 .net framework 4.5 时,代码按预期工作: 输出与示例相同:
The example displays output like the following: Instantiated object This instance of ExampleClass has been in existence for 00:00:00.0011060 Finalizing object This instance of ExampleClass has been in existence for 00:00:00.0036294
当我使用 dotnet core app 时,代码不起作用: 实际输出为:
PS C:\ws\test> dotnet run Instantiated object This instance of ExampleClass has been in existence for 00:00:00.0056874
那么,为什么这在 .NET Core 中有所不同呢?
答:
在垃圾回收器运行之前,不会进行终结。垃圾回收不会运行,除非它需要(例如,您的内存不足),或者您强制它运行。
尝试添加
System.GC.Collect();
并查看终结器是否在这种情况下运行。
评论
GC.Collect
GC.Collect()
将 Peter Duniho 和 Henk Holterman 评论中的信息汇总在一起,并进一步扩展:
此行为违反了 Microsoft 的 C# 5.0 规范和 Microsoft 的 C# 6.0 规范的当前草案,其中说:
在应用程序终止之前,将调用其所有尚未进行垃圾回收的对象的析构函数,除非此类清理已被禁止(例如,通过调用库方法)。
GC.SuppressFinalize
但这不是一个错误,.Net Core 故意偏离了 .Net Framework 行为,如 corefx 问题中所述:
目前,已尽最大努力在关机期间为所有可终结对象(包括可访问对象)运行终结器。为可访问对象运行终结器并不可靠,因为对象处于未定义状态。
...
建议
不要在关机时运行终结器(对于可访问或无法访问的对象)
...
根据该提案,不能保证所有可最终确定的对象都将在关闭之前完成。
大概正因为如此,ECMA 的 C# 5.0 规范削弱了此要求,因此 .Net Core 不会违反此版本的规范:
在应用程序终止之前,实现应尽一切合理努力为其所有尚未被垃圾回收的对象调用终结器 (§15.13),除非此类清理已被禁止(例如,通过调用库方法)。实现应记录无法保证此行为的任何条件。
GC.SuppressFinalize
评论