我在发布模式下构建 .NET6 控制台项目,当它从命令行启动时,终结器不会被调用。从 IDE 启动时成功调用终结器。
.NET Framework 4.8 - 从 cmd 和 IDE 调用终结器
.NET Core 3.1 - 没有从 IDE 和 cmd 调用终结器
是不是说要对project做一些设置?或者即使 GC.Collect() 被强制调用,我也不能依赖终结器?
namespace TestApp
{
public class Program
{
public static void Main(string[] args)
{
MyClass myClass = new MyClass();
var gen = GC.GetGeneration(myClass);
Console.WriteLine(gen);
myClass = null;
GC.Collect();
GC.WaitForPendingFinalizers();
Console.ReadKey();
}
}
public class MyClass
{
public MyClass()
{
Console.WriteLine("Ctor");
}
~ MyClass()
{
Console.WriteLine("Finalizer");
}
}
}
.exe 从命令行(cmd 和 powershell)启动时的输出:
角
0
项目从 IDE (Visual Studio) 启动时的输出:
角
0
完成
首先,如果你想要确定性的资源清理,你不应该依赖调用终结器,查看“当你知道的一切都是错误的”文章(p1,p2),实施
Dispose
模式。
中学 - 查看this discussion,似乎JIT以某种方式延长了
MyClass
的“最后”实例的生命周期。例如,以下将仅收集“第一个”对象:
for (int i = 0; i < 2; i++)
{
Thread.Sleep(1000);
NewFunction();
}
Console.WriteLine($"Collected: {MyClass.collected}");
Console.ReadKey();
[MethodImpl(MethodImplOptions.NoInlining)]
void NewFunction()
{
MyClass myClass = new MyClass();
var gen = GC.GetGeneration(myClass);
Console.WriteLine(gen);
myClass = null;
Console.WriteLine(myClass);
Collect();
}
[MethodImpl(MethodImplOptions.NoInlining)]
static void Collect()
{
GC.Collect();
GC.WaitForPendingFinalizers();
}
public class MyClass
{
private static int counter;
public static int collected;
public int Id { get; }
public MyClass()
{
Id = Interlocked.Increment(ref counter);
Console.WriteLine("Ctor");
}
~MyClass()
{
collected++;
Console.WriteLine($"Finalizer {Id}");
}
}
但是在循环和最终之间添加以下内容
Console.WriteLine
:
while (MyClass.collected != 2)
{
Thread.Sleep(500);
Collect();
}
触发正在收集和完成的两个实例。