从命令行启动项目时不调用 .NET6 终结器

问题描述 投票:0回答:1

我在发布模式下构建 .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
完成

c# garbage-collection .net-6.0 finalizer
1个回答
0
投票

首先,如果你想要确定性的资源清理,你不应该依赖调用终结器,查看“当你知道的一切都是错误的”文章(p1p2),实施

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();
}

触发正在收集和完成的两个实例。

同时检查 .NET 内存性能分析:为什么 GC 不收集这些对象?他们应该被收集起来!

© www.soinside.com 2019 - 2024. All rights reserved.