调试模式和发布模式下异常堆栈跟踪的区别

13

以下代码在调试模式和发布模式下会生成不同的异常堆栈跟踪:

static class ET
{
    public static void E1()
    {
        throw new Exception("E1");
    }
    public static void E2()
    {
        try
        {
            E1();
        }
        catch (Exception e)
        {

            throw;

        }
    }

    public static void Entry()
    {
        try
        {

            E2();
        }
        catch (Exception e)
        {           
            Console.WriteLine(e.StackTrace);
        }
    }
}

调试模式下的结果:

在 D:\myStudio\CSharp\CSharp4.0\MyCSharp\ExceptionHandling.cs 的 ET.E1() 中,第 47 行

在 D:\myStudio\CSharp\CSharp4.0\MyCSharp\ExceptionHandling.cs 的 ET.E2() 中,第 58 行

在 D:\myStudio\CSharp\CSharp4.0\MyCSharp\ExceptionHandling.cs 的 ET.Entry() 中,第 68 行

发布模式下的结果:

在 D:\myStudio\CSharp\CSharp4.0\MyCSharp\ExceptionHandling.cs 的 ET.E2() 中,第 55 行

在 D:\myStudio\CSharp\CSharp4.0\MyCSharp\ExceptionHandling.cs 的 ET.Entry() 中,第 68 行

请注意,在发布模式下结果中缺少了第一行。如何返回发布模式下的冒犯行。


1
E1 已被内联到 E2 中 - 这是一个有用的优化,但这意味着一些方法将在堆栈跟踪中缺失。 - Damien_The_Unbeliever
我相信这是按预期工作的。编译器在优化发布版本时可以自由地内联方法,这种情况下原始方法就不是创建的程序集的一部分。那对你来说有什么问题吗? - Jens
谢谢!我也认为它是内联的。我想使用[MethodImpl(MethodImplOptions.NoInlining)]是唯一的防止方法。 - Pingpong
1个回答

19

你可能看到的是内联的结果。在调试模式下编译代码时,内联总是被关闭的(这样调试才有意义)。在发布模式下编译代码时,编译器会删除某些方法(受许多规则的限制),并将它们的内容插入所有调用点中。通过消除方法调用开销,这可以提高这些方法的整体性能。


1
谢谢!我认为使用[MethodImpl(MethodImplOptions.NoInlining)]是防止这种情况发生的唯一方法。 - Pingpong
是的,但请记住这样做可能会影响性能。具体影响有多大可能存在争议。 - Chris Shain
1
但是像log4net这样的工具应该能够报告有问题的代码行,就好像它在调试模式下运行一样,即使它在发布模式下运行。如果是这种情况,它是如何实现的很有趣。 - Pingpong
无论如何,它们都不会显示内联方法,或者对l4n的调用将阻止该方法进行内联。没有查看它,我怀疑后者实际上相当可能。 - Chris Shain

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