80

选项的名称说明了一些事情,但 Visual Studio/编译器真正做了什么,真正的后果是什么?

编辑:如果你搜索谷歌,你可以找到这个地址,但这并不是我真正想要的。我想知道真正发生的事情。例如为什么循环的时间更少等等。

4

3 回答 3

65

如果没有优化,编译器会产生非常愚蠢的代码——每个命令都以非常直接的方式编译,因此它可以完成预期的事情。Debug 版本默认禁用优化,因为如果没有优化,生成的可执行文件会直接匹配源代码。

保存在寄存器中的变量

打开优化后,编译器会应用许多不同的技术来使代码运行得更快,同时仍然执行相同的操作。在 Visual C++ 中优化和未优化构建之间最明显的区别是变量值在优化构建中尽可能长时间地保存在寄存器中,而没有优化它们总是存储在内存中。这不仅会影响代码速度,还会影响调试。由于这种优化,调试器在您单步执行代码时无法可靠地获取变量值。

其他优化

编译器应用了多种其他优化,如/O 选项(优化代码)MSDN 文档中所述。有关各种优化技术的一般描述,请参阅Wikipedia Compiler Optimization 文章

于 2008-09-22T10:00:40.907 回答
18

来自保罗维克的博客:

  • 它删除了我们会发出以帮助调试的任何 NOP 指令。当优化关闭(并且调试信息打开)时,编译器将为没有任何实际 IL 关联但您可能希望在其上放置断点的行发出 NOP 指令。最常见的例子是“If”语句的“End If”——没有为 End If 发出实际的 IL,所以我们不发出 NOP,调试器不会让你设置断点在上面。打开优化会强制编译器不发出 NOP。

  • 我们对生成的 IL 进行简单的基本块分析,以删除任何死代码块。也就是说,我们将每个方法分成由分支指令分隔的 IL 块。通过快速分析块如何相互关联,我们可以识别出任何没有分支的块。因此,我们可以找出永远不会执行并且可以省略的代码块,从而使程序集更小。此时我们也做了一些小的分支优化——例如,如果你转到另一个 GoTo 语句,我们只优化第一个 GoTo 以跳转到第二个 GoTo 的目标。

  • 我们发出一个 DebuggableAttribute,并将 IsJITOptimizerDisabled 设置为 False。基本上,这允许运行时 JIT 以它认为合适的方式优化代码,包括重新排序和内联代码。这将产生更高效和更小的代码,但这意味着尝试调试代码可能非常具有挑战性(任何尝试过它的人都会告诉你)。我不知道 JIT 优化的实际列表——也许像 Chris Brumme 这样的人会在某个时候插话。总而言之,优化开关启用了可能使设置断点和单步执行代码变得更加困难的优化。

于 2008-09-22T10:03:04.863 回答
2

简短的回答是:使用 -Ox 并让编译器完成它的工作。

长答案:无法准确预测不同类型优化的效果。有时针对快速代码进行优化实际上会产生比针对大小进行优化时更小的代码。如果你真的想获得最后 0.01% 的性能(速度或尺寸),你必须对不同的选项组合进行基准测试。

此外,最新版本的 Visual Studio 具有更高级优化的选项,例如链接时优化和配置文件引导优化。

于 2008-09-22T09:14:56.477 回答