【问题标题】:finalizer not called after GC.Collect() [duplicate]在 GC.Collect() 之后未调用终结器 [重复]
【发布时间】:2020-12-05 21:42:17
【问题描述】:

我想我缺少一些基本的东西,希望你能提供帮助。下面的代码创建一个对象,删除引用并调用垃圾收集器。我的期望是 SomeClass 的终结器会在站在 Readline 时被调用。它没有。我尝试在循环中调用 GC.Collect,添加一些 Sleep() 调用以启动终结器线程。不会发生。

只有在 Main 结束时才会击中终结器,但令人惊讶的是它会被击中两次。我错过了什么?

class Program
{
    public static void Main(string[] args)
    {
        SomeClass some = new SomeClass("Hello World!");
        some = null;
        GC.Collect();
        GC.WaitForPendingFinalizers();
        Console.WriteLine("Done");
        Console.ReadLine();
    }
}

class SomeClass 
{
    string ss;
    public SomeClass(string s) { ss = s; }
    ~SomeClass()
    {
        var hash = this.GetHashCode();
    }
}

附录 在调试模式和发布模式下运行程序是有区别的。下面的程序在调试模式下生成Start - Done - Finalize,而在发布模式下,日志文件显示Start - Finalize - Done。后者是我所期望的。

class Program
{
    private static string logfile = @"c:\temp\log.txt";
    public static void Main(string[] args)
    {
        File.WriteAllText(logfile, "Start\n");
        SomeClass some = new SomeClass("Hello World!");
        some = null;
        GC.Collect();
        GC.WaitForPendingFinalizers();
        File.AppendAllText(logfile, "Done\n");
    }
}

class SomeClass 
{
    private static string logfile = @"c:\temp\log.txt";
    public string SomeString { get; set; }
    public SomeClass(string s) { SomeString = s; }
    ~SomeClass()
    {
        File.AppendAllText(logfile, "Finalize\n");
    }
}

【问题讨论】:

    标签: c# .net


    【解决方案1】:

    被垃圾回收的对象变得适合终结并被放入终结队列。 绝对不能保证这些终结器会运行

    我会将您重定向到 Eric Lippert 关于此的精彩帖子,适当地称为 "When everything you know is wrong." 特别是:

    误区:将变量设置为 null 会导致终结器在该变量之前引用的对象上运行。 将变量设置为 null 不会导致任何事情立即发生,除非更改变量。如果变量是对相关对象的最后一个活动引用,那么当垃圾收集器针对对象所在的任何一代运行收集器时,就会发现这一事实。(如果它完全运行,它可能不会运行。无法保证GC 运行。)

    即使是GC.Collect():

    误区:调用 GC.Collect() 会导致终结器运行。 不,它会导致收集发生。这可能会识别作为终结器候选对象的对象,但它不会强制调度终结器线程。如果这就是你想要的——请仅用于测试目的! — 然后拨打GC.WaitForPendingFinalizers()

    所以最好的成功机会是GC.WaitForPendingFinalizers()。但即便如此,请您参考帖子的其余部分 (and its sequel),不保证最终确定运行。不要依赖那个。

    我在this question 上写了更详细的解释,因此您可以将其作为进一步研究的起点。

    【讨论】:

    • 感谢 V0ldek 提供的宝贵信息。我发现了一个提示,在调试模式下,事情的工作方式不同。确实如此。我将在我最初的问题中添加一个附录。
    猜你喜欢
    • 1970-01-01
    • 2011-06-08
    • 1970-01-01
    • 2019-12-18
    • 1970-01-01
    • 2014-02-19
    • 1970-01-01
    • 2018-01-15
    • 1970-01-01
    相关资源
    最近更新 更多