I heard compiling in Release mode generates optimized code than in Debug mode, which is fine.
But is this optimization in the IL? is it in the machine code once the CLR runs it? is the metadata structure different from PE compiled in Release and Debug?
thanks
In VB there is a side-effect of Edit + Continue support compiled into the executable, which can cause a memory leak. It is affected by any event that is declared with the WithEvents keyword. A WeakReference keeps track of those event instances. Problem is, those WeakReferences are leaked if you run the app without a debugger. The rate at which the process consumes memory is highly dependent on how many instances of the class get created. The leak is 16 bytes per event per object.
Disclaimer: copied from Hans' answer here
See this Microsoft knowledge base article.
The cil differs, it is optimized. Since the machine code is a translation of the cil, it also differs. You can see it by yourself, just open the disassembly window in visual studio. Metadata should remain the same as you don't change the structure of class contracts between releases.
This is not an answer to the exact question. Just to add that you can purposefully mark which code has to be run in debug mode and which in release mode with the help of preprocessor markups.
So if you do this you'd get different IL generated.
Yes, there's some optimization in the IL - in particular, the debug version will include NOP instructions which make it easy for a debugger to insert break points, I believe. There are also potentially differences in terms of the level of debug information provided (line numbers etc).
I suggest you take a small sample program, compile it in both ways, and then look at the output in
ildasm
.The C# compiler doesn't do much optimization - the JIT compiler does most of that - but I think there are some differences.
Building in Release build turns on the /optimize compile option for the C# compiler. That has a few side-effects, the IL indeed changes but not a great deal. Notable is that the compiler no longer makes an effort to make the code perfectly debuggable. It for example skips an empty static constructor, it no longer emits the NOP opcodes that allows you to set a breakpoint on a curly brace and allows local variables with different scopes to overlap in a stack frame. Small stuff.
The most important difference is the [Debuggable] attribute that's emitted for the assembly, its IsJITOptimizerDisabled property is false.
Which turns on the real optimizer, the one that's built into the jitter. You'll find the list of optimizations it performs in this answer. Do note the usefulness of this approach, any language benefits from having the code optimizer in the jitter instead of the compiler.
So in a nutshell, very minor changes in the IL, very large changes in the generated machine code.