完成和GC.Collect

时间:2015-03-13 10:22:27

标签: .net garbage-collection

我试着明白,为什么会有不同的行为。

代码1 代码2 不同,只是注释行Console.WriteLine(h.ToString());

但在这种情况下,代码1 中的Console.Beep();会在 static void Main(string[] args)完成之前执行

代码2 Console.Beep();仅在static void Main(string[] args)完成(流程终止?)时执行。

请你解释一下,为什么会这样?

我尝试使用[+/-]优化设置调用代码 - 看起来它不依赖于它。

现在我没有WinDbg, - 反编译代码中的答案。

代码1:

class Program
{
    static void Main(string[] args) {
        var h = new Haha();

        // Console.WriteLine(h.ToString());

        GC.Collect();
        GC.WaitForPendingFinalizers();

        /* Console.Beep() calls here */

        Console.ReadKey();
    }
}

public class Haha
{
    ~Haha() {
        Console.Beep();
    }
}

代码2:

class Program
{
    static void Main(string[] args) {
        var h = new Haha();

        Console.WriteLine(h.ToString());

        GC.Collect();
        GC.WaitForPendingFinalizers();

        Console.ReadKey();

        /* Console.Beep() calls here */
    }
}

public class Haha
{
    ~Haha() {
        Console.Beep();
    }
}

1 个答案:

答案 0 :(得分:1)

在第一个例子中:

var h = new Haha()

该变量未在任何地方引用,因此将其删除。通过这种方式,Haha()在创建之后就不会被引用,因此可以随时使用GC。

在第二个示例中,引用了变量h,因此它具有引用它的块的“最大”生命周期(因此整个main)。编译器和GC可以检测到h的“最后”使用,并认为它在Console.WriteLine(最后一次使用h)之后被取消引用(缩短其生命周期),但是显然不这样做。

请注意,如果您在发布模式下运行程序+在没有调试器的情况下运行,代码2将给出(至少它给我)与代码1相同的结果。调试器,使其更容易调试,保证所有引用都是有效的,直到它们被声明的块结束(参见https://stackoverflow.com/a/7165380/613130)在Release模式下运行程序+ Run without Debugger我们解决了这个问题。

完成一些测试:让你需要更短的生命周期(同时): none 的调试信息(属性 - >构建 - >高级 - >调试信息)或者 pdb-only ,再加上没有调试器的程序(Ctrl + F5)。如果将“调试信息”设置为“完全”,则会在程序集中注入DebuggableAttribute,并且CLR不会尝试缩短变量的生命周期。如果您使用调试器运行,则相同。如果按命令行编译,则设置选项/debug等同于/debug:full(请参阅https://msdn.microsoft.com/en-us/library/8cw0bt21.aspx