WinDbg用于调试和发布版本的不同堆栈跟踪

时间:2014-07-21 06:41:31

标签: .net debugging windbg

我按照MSDN正确设置了Windbg。问题是当我在调试模式下获得转储文件时,我可以正确地看到调用堆栈(符号被正确加载)。

000000f758b6eac0 00007ffb5be60559 System.Number.StringToNumber(System.String, System.Globalization.NumberStyles, NumberBuffer ByRef, System.Globalization.NumberFormatInfo, Boolean)
000000f758b6eb20 00007ffb5b0cd791 System.Number.ParseInt32(System.String, System.Globalization.NumberStyles, System.Globalization.NumberFormatInfo)
000000f758b6ec70 00007ffafcc60214 ConsoleApplication1.Program.ConvertToInt(System.String)
000000f758b6ecb0 00007ffafcc60105 ConsoleApplication1.Program.Main()
000000f758b6f030 00007ffb5c3b4113 [GCFrame: 000000f758b6f030] 

当我在发布模式下获取转储文件时,缺少某些信息,特别是方法名称“ConvertToInt”,它在调试模式下可见。

00000081df98c710 00007ffafcc701e1 ConsoleApplication1.Program.Main() [C:\Written Programs\ConsoleApplication1\ConsoleApplication1\Program.cs @ 29]
00000081df98e6a8 00007ffb5c3eb915 [HelperMethodFrame: 00000081df98e6a8] 
00000081df98e790 00007ffb5be60559 System.Number.StringToNumber(System.String, System.Globalization.NumberStyles, NumberBuffer ByRef, System.Globalization.NumberFormatInfo, Boolean)
00000081df98e7f0 00007ffb5b0cd791 System.Number.ParseInt32(System.String, System.Globalization.NumberStyles, System.Globalization.NumberFormatInfo)
00000081df98e940 00007ffafcc700e0 ConsoleApplication1.Program.Main() [C:\Written Programs\ConsoleApplication1\ConsoleApplication1\Program.cs @ 23]

我在这里做错了吗? 再加上HelperMethodFrame是什么意思? 除了在调试模式下,即使没有程序.pdb文件,我仍然可以正确看到调用堆栈。究竟是什么.pdb文件用于。我已经阅读了定义和所有内容,只需要一个关于它如何与Windbg一起使用的实用答案?

1 个答案:

答案 0 :(得分:6)

这是完全正常的,您的Release版程序启用了抖动优化器。请阅读this answer了解其执行的优化类型。

您的Program.ConvertToInt()方法成为该列表中第一个项目符号的受害者。它有内联。内联是一种非常基本的优化策略,而不是发出一个CALL来调用该方法,优化器注入了该方法的代码。对于不生成大量机器代码的小方法,会发生这种情况。这是一个重要的优化,它可以避免设置调用堆栈和分支,它可以轻松地节省一些纳秒。并使更多优化可用,包括但不限于如果优化器可以确定特定参数使得运行代码变得不必要,则使整个方法开销消失。

HelperMethodFrame是一个深层次的CLR实现细节,它发生在所谓的FCall调用CLR中的函数中。调用不会设置自己的堆栈帧,而是捎带到程序的堆栈帧上。 FCall ==“快速调用”,mental images是C#代码直接调用本机C ++代码而没有任何互操作。但是当该函数确定无论如何都需要堆栈帧以便正确地发出异常时,它会动态地构建一个异常。没有名称与之相关联。 this blog post中的fcalls有一些不透明的背景。

这些优化当然会使调试版本内置代码大大复杂化。这是调试配置存在的核心原因,它禁用优化,因此程序更容易调试。您可以将[MethodImpl(MethodImplOptions.NoInlining)]属性应用于某个方法,以防止它被内联。这不是你应该做的大事,因为它是绝对杀手但对这种代码完全合理,因为无论如何将字符串解析为数字都是昂贵的。