Home:ALL Converter>Different C# Output Between Release and Debug

Different C# Output Between Release and Debug

Ask Time:2015-04-15T03:54:19         Author:Tom Baxter

Json Formatter

I've a little C# program here that produces different output between the Debug and Release versions. The empty output from the Release version is, I think, consistent with the C# Language Specification. This program should not produce output, yet the Debug version does.

I've run both the Release and Debug versions from the command line (outside the VS environment) and get the same inconsistent output. I've decompiled the Debug version (using ILDASM) and then re-compiled it with ILASM. When I do this, the newly compiled program behaves just like the Release version. I can only imagine that when I de-compile and then re-compile something is being left out but I've not been able to determine what's different.

Regarding the EXE file size: Both the Release and Debug versions produced by VS have the same file size: 5,120 bytes. When I de-compile and re-compile, both versions again have the same, but smaller file size: 3,072.

The program is quite small and I've looked at the IL in Reflector and I can't see anything that would cause a difference in output.

Does anyone have a (hopefully detailed) explanation of exactly why there is a difference?

Please note that I'm not trying to make the Debug and Release versions consistent, necessarily, I want to understand why they are not.

Recall what I said above -- both the Debug and Release versions produce different output even when run from the command line. If you tell me the runtime is doing some kind of optimization for the Release version but not for the Debug version then there must be something embedded in the Debug/Release version assemblies that tell the runtime to turn on/off optimizations. What is that embedded "something" and why does it not carry over when using ILDASM/ILASM?

Here's the code:

using System;

class Test {
    static int value = 0;
    static int a = Initialize("Assigning a");
    static int b = Initialize("Assigning b");
    static String name = "Fred";
    static int c = Initialize("Assigning c");

    static int Initialize(String mssg) {
        ++value;
        Console.WriteLine("In Initialize() :: {0}, name={1}, returning {2}", mssg, name, value);
        return value;
    } // Initialize()

    static void Main() {
    } // Main()
} // class Test

And here is the output from the Visual Studio generated Debug version:

In Initialize() :: Assigning a, name=, returning 1
In Initialize() :: Assigning b, name=, returning 2
In Initialize() :: Assigning c, name=Fred, returning 3

Running the release version generates no output.

Author:Tom Baxter,eproduced under the CC 4.0 BY-SA copyright license with a link to the original source and this disclaimer.
Link to original article:https://stackoverflow.com/questions/29636243/different-c-sharp-output-between-release-and-debug
pm100 :

The static class initializer is not called until its needed. Clearly the debug and release versions decided differently about when its needed. IN particular my guess is that the release build optimized the main out entirely and so never loaded the class. It seems to have decided that since main does nothing it can optimize everything out - in this case it seems to be a bad decision",
2015-04-14T20:06:49
Blorgbeard :

Turning optimizations on (release mode) affects the IL generated, as well as the behaviour of the JITter. \n\nYou are probably seeing the initialization of the unused variables being eliminated by the JITter. \n\nThis explains the ILDASM/ILASM behaviour, and the fact that there's no significant difference in the IL.\n\nI suspect this behaviour is controlled by the value of the CorDebugJITCompilerFlags flag somewhere in the CLR header.. See Does C# compiler /optimize command line option affect JITter?",
2015-04-14T20:11:26
Tom Baxter :

After more research, I found the answer I was looking for (thanks to Blogbeard for pointing me in the right direction).\n\nIt turns out that when you compile for Debug, the generated assembly is, by default, decorated with a DebuggableAttribute whose \"Debugging Mode\" is\n\nDebuggableAttribute.DebuggingModes.DisableOptimizations | DebuggableAttribute.DebuggingModes.Default\n\n\nIt is apparently this combination of flags that seem to turn off JIT optimization, resulting in the output I saw in the Debug version of the program. The Release version of the program has a different \"Debugging Mode\", allowing JIT optimization to proceed.\n\nOf course, if you manually set the DebuggableAttribute in the AssemblyInfo (as I did during testing) for the Debug build, you can override the default behavior.\n\nI'm sure there are some CLR/JIT Lawyers out there who can explain in greater detail.",
2015-04-14T22:16:59
yy