有人问了这样的问题:"我工作的公司正极力反对用生成的调试信息构建发布模式二进制文件,这也是我注册该类的原因之一。他们担心演示会受到影响。我的问题是,在发布模式下生成符号的最佳命令行参数是什么?还有什么地方我可以参考,以表明不应该有性能问题。“

回答是:不,生成PDB文件对性能没有任何影响。至于我也可以给你指出的参考资料,我在网上还没有找到任何能回答确切问题的资料,所以让我依次介绍.NET和本机开发。

Eric Lippert写了一篇很棒的文章,优化开关是做什么的?他讨论了编译器和即时(JIT)编译器所做的优化。(基本上,您可以将其总结为JITter完成所有实际的优化工作。)C#和VB.NET编译器之间的切换有些混乱,因为有四个不同的/debug开关,/debug,/debug+,/debug:full和/debug:pdb。我之所以造成这种混乱,是因为我认为/debug:pdb只做了一些与其他三个/debug开关不同的事情,它们对发布版本的构建更好。

所有四个开关都做相同的事情,因为它们会生成一个PDB文件,但为什么有四个开关做相同的事情?微软开发人员真的喜欢解析稍微不同的命令行选项吗?真正的原因是:历史。在.NET1.0中有差异,但在.NET2.0中没有。看起来.NET4.0将遵循相同的模式。在与CLR调试团队进行了反复检查之后,没有任何区别。

控制抖动是否执行调试生成的是/optimize开关。使用/optimize构建-将在程序集中添加一个属性DebuggableAttribute,并将DebuggingMode参数设置为DisableOptimizations。不需要罗兹学者就能弄明白,禁用优化正是按照它所说的做的。

归根结底,您希望使用/optimize+和任何/debug开关来构建发布版本,以便可以使用源代码进行调试。阅读Visual Studio文档,了解如何在不同类型的项目中设置这些开关。

很容易证明这些是最佳开关。使用我的示例程序,我用/optimize+和/debug编译了一个构建,用just/optimize+编译了另一个构建。这与/debug+和/debug相同,而另一个与/optimize+/debug:pdbonly相同,显示了不同之处,这是我们错误的根源。编译之后,我使用ILDASM和以下命令行从二进制文件中获取原始信息

ILDASM /out=Paraffin.IL Paraffin.exe

使用diff工具,您将看到两个构建之间的IL本身是相同的。主要区别在于程序集的DebuggableAttribute声明。在build/optimize+和a/debug开关时,一个DebuggingMode.IgnoreSequencePoints被传递给DebuggableAttribute,告诉JIT编译器不需要加载PDB文件就可以正确地对IL进行JIT。DebuggingMode的值。默认值也为或,但该值被忽略。

与.NET一样,构建PDB文件与优化无关,因此对应用程序的性能没有影响。如果你的经理用说是“害怕业绩会受到影响”,我就告诉他们。(不幸的是,我遇到的经理中,说这话的人比我想象的还多)。

NET非常简单,因为实际上只有两个开关,所以适当的优化开关取决于许多单独的应用程序因素。我能告诉你的是在发布版本中正确生成PDB文件需要设置哪些开关。

对于编译器CL.EXE,您需要添加/Zi以使其将调试符号放入.OBJ文件。对于链接器LINK.EXE,需要指定三个选项。第一个是/DEBUG,它告诉链接器生成一个PDB文件。但是,该开关还告诉链接器这是调试生成。这不太好,因为这会影响二进制文件的性能。基本上,使用/调试时发生的情况是链接器链接速度更快,因为它不再查找单个引用。如果使用OBJ中的一个函数,链接器会将整个OBJ抛出到输出二进制文件中,因此现在有一堆死函数。

要告诉链接器只需要引用的函数,需要添加/OPT:REF作为第二个开关。第三个开关是/OPT:ICF,它启用了COMDAT折叠。有一个术语你不是每天都听到。基本上,这意味着在生成二进制文件时,链接器将查找具有相同代码的函数,并且只生成一个函数,但使多个符号指向一个函数。

如果您想自己在本机二进制文件上测试差异,以查看对生成PDB文件有什么影响,这几乎和.NET二进制文件一样简单。Visual Studio附带了一个很好的小程序DUMPBIN,它可以告诉您关于可移植可执行文件的更多信息使用/DISASM开关运行它以获得二进制文件的反汇编。

标签: none

添加新评论