0

I try to understand, why there is different behavior.

Code 1 different from Code 2 just with comment line Console.WriteLine(h.ToString());.

But in this case Console.Beep(); in Code 1 executes before static void Main(string[] args) finished.

In Code 2 Console.Beep(); executes only when static void Main(string[] args) finished (process terminated?).

Can you please explain me, why is it so?

I tried to call codes with [+/-] Optimization setting- looks like it doesn't depend on it.

Right now i dont have WinDbg,- mb the answer in decompiled code.

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

Code 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();
    }
}
Maxim Zhukov
  • 10,060
  • 5
  • 44
  • 88

1 Answers1

1

In the first example:

var h = new Haha()

the variable isn't referenced anywhere, so it is removed. In this way the Haha() isn't referenced anywhere just after being created and so can be GC at any time.

In the second example the variable h is referenced, so it has a "maximum" lifetime of the block in which it is referenced (so the whole main). The compiler and the GC could detect the "last" use of h and consider it to be unreferenced just after the Console.WriteLine (the last use of h) (shortening its lifetime), but clearly don't do so.

Note that if you run your program in Release mode + Run without Debugger, the Code 2 will give (at least it gives to me) the same result as Code 1. The debugger, to make it easier to debug, guarantee that all the references are valid until the end of the block where they are declared (see https://stackoverflow.com/a/7165380/613130) Running the program in Release mode + Run without Debugger we solve this.

Done some tests: to have the shorter lifetime you need to have (at the same time): Debug Info (Properties->Build->Advanced->Debug Info) at none or pdb-only, plus run the program without debugger (Ctrl+F5). If you set the Debug Info at Full, then a DebuggableAttribute is injected in the assembly, and the CLR won't try to shorten the lifetime of the variables. The same if you run with a debugger. If you compile by command line, setting the option /debug is equivalent to /debug:full (see https://msdn.microsoft.com/en-us/library/8cw0bt21.aspx)

Community
  • 1
  • 1
xanatos
  • 109,618
  • 12
  • 197
  • 280
  • Brilliant answer, thank you! I knew about `guarantee that all the references are valid until the end of the block where they are declared` if program runs with debugger, but i got mistake- i thought with/without debug manipulating with configuration (Debug/Release build), but, really, it manipulates with `Run` / `Run without Debugger` (F5/Ctrl + F5) – Maxim Zhukov Mar 13 '15 at 13:56