5

为了能够正确调试发布版本,需要一个 PDB 文件。当编译器使用不同类型的优化(FPO、PGO、内在函数、内联等)时,PDB 文件是否会变得不那么可用?如果是这样,优化的影响是严重的还是仅仅导致相邻的代码行混淆?

(我使用的是 VC2005,并且总是会选择可调试性而不是优化性能 - 但问题很笼统)

4

4 回答 4

7

是的,优化后的代码不易调试。不仅缺少一些信息,而且一些信息会非常具有误导性。

我认为最大的问题是局部变量。编译器可以使用相同的堆栈地址或在整个函数中为多个变量注册。正如其他海报所提到的,有时甚至弄清楚“this”指针是什么可能需要一些时间。在调试优化代码时,您可能会看到当前行在单步执行时跳来跳去,因为编译器重新组织了生成的代码。如果您使用 PGO,这种跳跃可能会变得更糟。

如果您有一个 PDB,FPO 不应过多影响可调试性,因为 PDB 包含展开 FPO 帧堆栈所需的所有信息。当使用需要在没有符号的情况下进行堆栈跟踪的工具时,FPO 可能会成为问题。对于许多项目而言,如今 FPO 的性能优势并没有超过对可诊断性的影响。因此,MS 决定不使用 FPO 优化构建 Windows Vista ( http://blogs.msdn.com/larryosterman/archive/2007/03/12/fpo.aspx )。

我更喜欢调试未优化的代码,但这并不总是可能的 - 一些问题只能用优化的代码重现,客户故障转储来自已发布的构建,并且有时无法进行调试私有部署。通常在调试优化代码时,我使用反汇编视图——反汇编永远不会说谎。

这一切都适用于windbg,因为我使用它进行所有本机代码调试。Visual Studio 的调试器可能会更好地处理其中一些情况。

于 2009-02-20T00:47:46.273 回答
2

是的。有时它可能很严重,尽管这通常更多是代码内联或重新排序的结果。

局部变量也可能无法准确显示在监视窗口中,因为它们可能仅存在于寄存器中,并且在切换堆栈帧时可能无法正确显示。

于 2009-02-18T21:56:09.890 回答
2

优化会严重影响任何平台上的调试(不仅仅是 VC 的 PDB 文件)。

正是由于您提到的原因,函数内联在某些情况下可能会完全混淆哪些指令属于哪个函数(因为有时它们属于两者)。

还有一个常见的优化是执行“脏”堆栈帧(GCC 中的 -fomit-frame-pointer),这会导致代码不跟踪堆栈顶部。这很好,它为其他操作释放了一个额外的寄存器(x86 上的 ebp)。但这使得展开堆栈以查看实际情况几乎是不可能的。这也使得在堆栈上找到局部变量和函数参数几乎是不可能的。

一般来说:不要期望从“发布”版本中获得有用的调试信息。如果调试很重要,即使在发布时,那么您应该改为“发布”调试版本。

于 2009-02-18T21:59:28.277 回答
2

除了局部变量之外,“this”指针通常在优化构建中被优化掉。有时可以通过在调用堆栈中上升到对象指针或引用作为未优化变量存在的点来解决此问题。

一般来说。优化构建中的单步通常或多或少地工作,并让人们看到代码做出了哪些逻辑决策。检查这些决策所依据的数据通常要复杂得多。

于 2009-02-18T22:09:46.787 回答