堆栈跟踪优化

3

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

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

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

在上面的代码片段中,设置ErrorMessage属性时,我调用了LogError方法,该方法捕获堆栈跟踪并将其写入日志文件。
MethodA()
 {
   Logger obj=new Logger();
   obj.ErrorMessage="Failure";
 }

在x86平台上,堆栈跟踪包含两个堆栈帧。一个是methodA方法的堆栈帧,另一个是ErrorMessage属性的setter方法的堆栈帧。
在x64平台上,堆栈跟踪只包含methodA方法的一个堆栈帧,没有ErrorMessage属性的setter方法的堆栈帧。
有人能向我解释一下在获取堆栈跟踪时优化是如何发生的吗?

MethodA 在哪里被调用了?这段代码不完整。 - Cody Gray
转帖:http://social.msdn.microsoft.com/Forums/en/csharplanguage/thread/6aa690fc-d2f4-4d04-9dca-cf9d5a445724 - Cody Gray
2个回答

3
当我在测试套件中尝试获取堆栈跟踪输出时,我没有看到x64和x86输出之间的任何区别。(虽然我并不指望有区别,但我总是想挑战我的假设!)
唯一会看到调用堆栈中有区别的情况是当你以发布模式编译代码时。这时,JITter通常会内联简单的方法调用,例如你的属性设置器。(是的,如果你反射发布模式下的代码,你仍然会看到独立的方法;只有当方法被JITted时才会看到这种差异)
这意味着,在调试模式下,属性设置器将出现在调用堆栈中:
   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)

这种优化可以在项目属性的“生成”选项卡中进行配置。当您在“配置”下拉菜单中在Debug和Release之间切换时,您会看到“优化代码”复选框中的差异。是的,您可以关闭发布版本的编译器优化,但这可能会影响您的应用程序性能,我不推荐这样做。


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有所不同,甚至包括它是否决定内联方法调用。 - Cody Gray

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接