Should I compile release builds with debug info as "full" or "pdb-only"?
In Visual Studio for a C# project, if you go to Project Properties > Build > Advanced > Debug Info you have three options: none
, full
, or pdb-only
.
Which setting is the most appropriate for a release build?
So, what are the differences between full
and pdb-only
?
If I use full
will there be performance ramifications? If I use pdb-only
will it be harder to debug production issues?
I would build with pdb-only
. You will not be able to attach a debugger to the released product, but if you get a crash dump, you can use Visual Studio or WinDBG to examine the stack traces and memory dumps at the time of the crash.
If you go with full
rather than pdb-only
, you'll get the same benefits, except that the executable can be attached directly to a debugger. You'll need to determine if this is reasonable given your product & customers.
Be sure to save the PDB files somewhere so that you can reference them when a crash report comes in. If you can set up a symbol server to store those debugging symbols, so much the better.
If you opt to build with none
, you will have no recourse when there's a crash in the field. You won't be able to do any sort of after-the-fact examination of the crash, which could severely hamper your ability to track down the problem.
A note about performance:
Both John Robbins and Eric Lippert have written blog posts about the /debug
flag, and they both indicate that this setting has zero performance impact. There is a separate /optimize
flag which dictates whether the compiler should perform optimizations.
WARNING MSDN documentation for /debug switch (In Visual Studio it is Debug Info) seems to be out-of-date! This is what it has which is incorrect
If you use /debug:full, be aware that there is some impact on the speed and size of JIT optimized code and a small impact on code quality with /debug:full. We recommend /debug:pdbonly or no PDB for generating release code.
One difference between /debug:pdbonly and /debug:full is that with /debug:full the compiler emits a
DebuggableAttribute
, which is used to tell the JIT compiler that debug information is available.
Then, what is true now?
- Pdb-only – Prior to .NET 2.0, it helped to investigate the crash dumps from released product (customer machines). But it didn't let attaching the debugger. This is not the case from .NET 2.0. It is exactly same as Full.
- Full – This helps us to investigate crash dumps, and also allows us to attach debugger to release build. But unlike MSDN mentions, it doesn't impact the performance (since .NET 2.0). It does exactly same as Pdb-only.
If they are exactly same, why do we have these options? John Robbins (windows debugging god) found out these are there for historical reasons.
Back in .NET 1.0 there were differences, but in .NET 2.0 there isn’t. It looks like .NET 4.0 will follow the same pattern. After double-checking with the CLR Debugging Team, there is no difference at all.
What controls whether the JITter does a debug build is the /optimize switch. <…>
The bottom line is that you want to build your release builds with /optimize+ and any of the /debug switches so you can debug with source code.
then he goes on to prove it.
Now the optimization is part of a separate switch /optimize
(in visual studio it is called Optimize code
).
In short, irrespective of DebugInfo setting pdb-only or full, we will have same results. The recommendation is to avoid None since it would deprive you of being able to analyze the crash dumps from released product or attaching debugger.
You'll want PDB only, but you won't want to give the PDB files to users. Having them for yourself though, alongside your binaries, gives you the ability to load crash dumps into a debugger like WinDbg and see where your program actually failed. This can be rather useful when your code is crashing on a machine you don't have access to.
Full debug adds the [Debuggable] attribute to your code. This has a huge impact on speed. For example, some loop optimizations may be disabled to make single stepping easier. In addition, it has a small effect on the JIT process, as it turns on tracking.
I'm in the process of writing a unhandled exception handler and the stack trace includes the line number when pdb-only is used, otherwise I just get the name of the Sub/Function when I choose None.
If I don't distribute the .pdb I don't get the line number in the stack trace even with the pdb-only build.
So, I'm distributing (XCOPY deploy on a LAN) the pdb along with the exe from my VB app.