一文搞懂C#实时调试时,程序数据库文件.pdb(符号文件)的作用。延伸搞懂Debug/Release、AnyCPU(首选32位)/x86/x64/ARM的区别

一、准备工作


MS引用:在 Visual Studio 调试器(C#、C++、Visual Basic、F#)中指定符号 (.pdb) 和源文件

MS引用:为 C#、ASP.NET 或 Visual Basic 项目 (.NET Framework) 生成符号文件

MS引用:用于控制编译器输出的 C# 编译器选项


1、首先,我们需要一个控制台程序,代码很简单,ConsoleApp1控制台程序在主程序中,调用ClassLibrary1类库中Class1下的Do方法,如下:

2、生成AnyCPU或任意目标平台,代码的目录结构如下:

3、然后在bin/Debug目录下,双击运行控制台程序,按照代码逻辑,程序堆栈会停在“Console.ReadLine();”这一行;

4、(验证正常调试过程.pdb的用处)打开VS,通过“继续但无需代码”进入,选择“调试”-“附加到进程”,输入程序集名称,找到该进程,选择“附加”;

 5、附加进程ok后,点击调试的“全部中断”,看到断点停留在了“Console.ReadLine();”这一行:

二、移除.pdb会如何

 6、保持程序状态,需要做的是:

①将“..\bin\Debug\ConsoleApp1.pdb”重命名为“ConsoleApp1_Temp.pdb”

②将“..\obj\Debug\ConsoleApp1.pdb”重命名为“ConsoleApp1_Temp.pdb”

(obj下的是源.pdb文件,bin中的是源.pdb文件的副本;同样obj和bin下的exe也是如此;此处可以去了解下编译的过程,是先生成obj下的内容,再将运行时需要的文件拷贝到bin下)

(编译时,.pdb的路径会在被记录在exe程序中,这也是为什么要做②的原因)

7、VS重新进行附加进程,点击“全部中断”,会得到“处于中断模式”的结果,但由于缺少.pdb所以无法定位具堆栈:

 三、移除本地代码会如何

7、保持程序状态,恢复在步骤6中所做的,对obj和bin下.pdb的重命名,然后需要做的是:

①将源代码文件“Program.cs”重命名为“Program_Temp.cs”

8、VS重新进行附加进程,点击“全部中断”,会得到“未找到源”的结果,能够在“局部变量”和“调用堆栈”选项卡中看到内容,却没有对应源代码定位:

 四、总结

        首先,为什么选择附加到进程,而不是在工程中将“活动解决方案平台配置”设置为“Debug”进行启动?——Debug模式每次启动时,obj下的源.pdb会默认生成,并拷贝到bin输出目录中。

        其次,上述步骤是在“生产环境下使用.pdb加上源码进行调试”的场景。(有人会说生产环境下不是应该放Release版本吗,也不会有.pdb啊。那就接着往下看,实际是因为默认生成Release时被优化编码导致不能准确命中断点,并且在“生成”-“高级设置”下未选择编译出pdb而已)。

        最后,.pdb记录的是调试信息,调试信息需要与源代码对应。实时调试时,需要将.pdb和要调试的单个或多个源码文件拷贝到生产环境目标机器上,选择附加进程后,exe或dll作为模块,pdb作为模块的符号(“调试”-“窗口”-“模块”-右键“exe或dll”模块名称-选择.pdb路径),源代码作为调试源文件(“解决方案资源管理器”-右键“解决方案'Solution1'(0个项目)”-“属性”-“调试源文件”-添加.cs所在文件夹),即可完成命中断点后跳转到所在代码行。

        具体操作见引用:PDB是什么文件?PDB文件格式详解


五、拓展——Debug和Release的区别

五-一、正常调试Release

1、右键“ConsoleApp1”工程-“属性”-“生成”-“高级”;

2、在默认情况下,将“配置”设置为Debug和Release时,我们能看到的区别在于优化编码这一项,Debug时默认“不选中”即“不优化编码”;Release时默认“选中”即“优化编码”。

3、此时,按上述流程同样对Release下的exe进行调试,会得到提示,并选择“继续调试”:

 4、点击“全部中断”,并不会命中当前堆栈“Console.ReadLine();”这一行,且“局部变量”和“调用堆栈”标签页中并无内容。

 五-二、取消“优化编码”调试Release

        不再贴图,直接放出结果,如同我们调试Debug一样

五-三、结论

        Debug和Release在使用VS调试时,主要区别在于是否进行了“优化编码”(实际上即使配置完全一致,对比16进制仍会返现两者不尽相同,比如生成时间戳、代码段地址)。

        而优化导致的结果,个人理解就是:

是否能够通过.pdb和源码,在正常的生产环境中,附加到进程并“准确”命中断点(优化编码后的部分断点也能命中)

 

六、拓展——AnyCPU(首选32位)/x86/x64/ARM的区别

(以下引用MS原文)        

PlatformTarget

指定 CLR 的哪个版本可以运行程序集。

XML复制

<PlatformTarget>anycpu</PlatformTarget>
  • anycpu(默认值)将程序集编译成可在任意平台上运行。 您的应用程序将尽可能作为 64 位进程运行;当只有 32 位模式可用时,才会回退到 32 位。
  • anycpu32bitpreferred 将程序集编译成可在任意平台上运行。 在同时支持 64 位和 32 位应用程序的系统上,您的应用程序将以32 位模式运行。 只能为面向 .NET Framework 4.5 或更高版本的项目指定此选项。
  • ARM 将程序集编译成可以在具有高级 RISC 计算机 (ARM) 处理器的计算机上运行。
  • ARM64 编译程序集以在由 64 位 CLR 在具有支持 A64 指令集的高级 RISC 计算机 (ARM) 处理器的计算机上运行。
  • x64 将程序集编译成可由支持 AMD64 或 EM64T 指令集的计算机上的 64 位 CLR 运行。
  • x86 将程序集编译成可由 32 位、x86 可兼容 CLR 运行。
  • Itanium 将程序集编译成可由配有 Itanium 处理器的计算机上的 64 位 CLR 运行。

在 64 位 Windows 操作系统上:

  • 用 x86 编译的程序集将在 WOW64 下运行的 32 位 CLR 上执行。
  • 用 anycpu 编译的 DLL 将在加载它的进程所在的同一 CLR 上执行。
  • 用 anycpu 编译的可执行文件将在 64 位 CLR 上执行。
  • 用 anycpu32bitpreferred 编译的可执行文件将在 32 位 CLR 上执行。

anycpu32bitpreferred 设置只对可执行文件 (.EXE) 有效,并且需要 .NET Framework 4.5 或更高版本。 

猜你喜欢

转载自blog.csdn.net/qq_23958061/article/details/130223918