【问题标题】:stacktrace optimization堆栈跟踪优化
【发布时间】:2011-04-11 08:48:05
【问题描述】:

在我的 C# 应用程序中,我使用堆栈跟踪来捕获方法名称和文件名以防失败。

x86 和 x64 平台之间的堆栈跟踪存在一些差异。

public string ErrorMessage
    {
      set
        {
         _strErrorMessage = "Error : " + value;
         //Call the method to log error.
         LogError(value);
        }
    }

在上面的代码sn-p中,我在设置ErrorMessage属性的同时,调用了LogError方法,该方法正在捕获堆栈跟踪并将其写入日志文件。

MethodA()
 {
   Logger obj=new Logger();
   obj.ErrorMessage="Failure";
 }

在这种情况下,在 x86 平台上,堆栈跟踪包含两个堆栈帧。一个用于 methodA,另一个用于 ErrorMessage 属性的设置器。

在 x64 平台上,堆栈跟踪仅包含一个用于方法 A 的堆栈帧,并且没有用于 ErrorMessage 属性的设置器的堆栈帧。

任何人都可以向我解释在获取堆栈跟踪时优化是如何发生的吗?

【问题讨论】:

标签: c# .net wpf 64-bit stack-trace


【解决方案1】:

当我尝试在测试工具中获取堆栈跟踪输出时,我看不出 x64 和 x86 输出之间有任何区别。 (我没想到,但我一直想挑战我的假设!)。

我希望看到调用堆栈有所不同的唯一情况是当您在 release 模式下编译代码时。当你这样做时,JITter 通常会内联简单的方法调用,例如您的财产的设置者。 (是的,如果您反思您的发布模式代码,您仍然会看到单独的方法;只有当方法被 JITted 时,您才会看到这种差异)

这对你来说意味着在调试中,setter 将出现在调用堆栈中:

   at ConsoleApplication5.Program.set_ErrorMessage(String value)
   at ConsoleApplication5.Program.MethodA()
   at ConsoleApplication5.Program.Main(String[] args)

但是当你在发布模式下编译它时,set_ErrorMessage 中的代码将被内联到 MethodA 中,这意味着你只会看到这个:

   at ConsoleApplication5.Program.MethodA()
   at ConsoleApplication5.Program.Main(String[] args)

此优化可在“构建”选项卡上的项目属性中进行配置。当您在“配置”下拉列表中切换“调试”和“发布”时,您会在“优化代码”复选框中看到不同之处。是的,您可以关闭发布版本的编译器优化,但这样可能会影响应用程序的性能,我不建议这样做。

【讨论】:

    【解决方案2】:

    我怀疑在 x64 上,JIT 会更积极地进行内联(优化)。尝试执行以下操作以查看是否是这种情况,或者仅在调试模式下运行,在该模式下应该关闭影响调试的优化:

        public string ErrorMessage
        {
          [MethodImplAttribute(MethodImplOptions.NoInlining)]
          set
            {
             _strErrorMessage = "Error : " + value;
             //Call the method to log error.
             LogError(value);
            }
        }
    

    【讨论】:

    • 是的,这似乎是一个合理的理论。 64 位 JITter 的处理方式通常与 32 位 JITter 不同,具体到它决定是否内联方法调用。
    猜你喜欢
    • 1970-01-01
    • 2014-03-29
    • 2011-05-25
    • 2011-05-13
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多