我试着明白,为什么会有不同的行为。
代码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();
}
}
答案 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)