调试和发布版本之间的性能差异

我必须承认,通常我不会在我的程序中调试和发布配置之间切换,而且我通常选择进行调试配置,即使这些程序实际部署在客户的地方。

据我所知,这些配置之间的唯一区别是,如果您不手动更改它,则Debug将定义DEBUG常量,并且Release将检查Optimize代码。

所以我的问题实际上是双重的:

  • 这两种配置有很大的性能差异。 是否有任何特定类型的代码会导致性能差异很大,还是实际上并不那么重要?

  • 是否有任何类型的代码在Debug配置下可以正常运行,在Release配置下可能会失败,或者您是否可以确定在Debug配置下测试并正常工作的代码也能正常工作。


  • C#编译器本身不会在发布版本中改变发布的IL。 值得注意的是,它不再发出允许您在大括号上设置断点的NOP操作码。 最重要的是内置于JIT编译器中的优化器。 我知道它会进行以下优化:

  • 方法内联。 方法调用被注入方法的代码所取代。 这是一个很大的问题,它使得属性访问器基本上是免费的。

  • CPU寄存器分配。 局部变量和方法参数可以保持存储在CPU寄存器中,而无需(或不太频繁)存储回栈帧。 这是一个很大的问题,因为调试优化代码非常困难。 并赋予volatile关键字一个含义。

  • 数组索引检查消除。 使用数组时一个重要的优化(所有的.NET集合类都在内部使用数组)。 当JIT编译器可以验证循环从不索引数组越界时,它将消除索引检查。 大的一个。

  • 循环展开。 通过在体内重复代码4次,循环次数减少,小身体循环得到改善。 降低分支成本并提高处理器的超标量执行选项。

  • 死码消除。 像if(false){/.../}这样的语句完全被删除。 这可能是由于不断的折叠和内联。 其他情况下,JIT编译器可以确定代码没有可能的副作用。 这种优化使分析代码非常棘手。

  • 代码吊装。 不受循环影响的循环内的代码可以移出循环。 C编译器的优化器将花更多的时间寻找提升机会。 然而,由于所需的数据流分析而导致的昂贵的优化,并且抖动无法承受时间,因此只能提供明显的情况。 迫使.NET程序员写出更好的源代码并提升自己。

  • 常见的子表达式消除。 x = y + 4; z = y + 4; 变成z = x; 在像dest [ix + 1] = src [ix + 1]这样的语句中很常见; 为了可读性而编写,而不引入辅助变量。 没有必要妥协的可读性。

  • 持续折叠。 x = 1 + 2; 变成x = 3; 这个简单的例子很早就被编译器发现了,但是在其他优化使这成为可能的时候发生在JIT时间。

  • 复制传播。 x = a; y = x; 变成y = a; 这有助于寄存器分配器做出更好的决策。 这对于x86抖动来说是个大问题,因为它没有几个寄存器可以使用。 选择合适的音色对演奏至关重要。

  • 这些都是非常重要的优化,例如,在分析应用程序的Debug版本并将其与Release版本进行比较时,这些优化可能会产生很大的差异。 只有当代码处于关键路径时,这才是真正重要的,你编写的5%到10%的代码实际上会影响程序的性能。 JIT优化器不够智能,无法知道什么是关键,它只能应用所有代码的“转为11”拨号。

    这些优化对程序执行时间的有效结果常常受到在别处运行的代码的影响。 读取文件,执行dbase查询等等。使JIT优化器的工作完全不可见。 它并不介意,但:)

    JIT优化器是非常可靠的代码,主要是因为它已经被测试了数百万次。 在您的程序的发布版本中出现问题极为罕见。 但它确实发生。 x64和x86抖动在结构上都有问题。 x86抖动在浮点一致性方面存在问题,当浮点计算的中间体以80位精度保存在FPU寄存器中时,会产生细微差别的结果,而不是在刷新到内存时截断。


  • 是的,有许多性能差异,这些都适用于您的代码。 调试很少进行性能优化,并且发布模式非常多;

  • 只有依赖于DEBUG常量的代码才能在发布版本中执行不同的操作。 除此之外,你不应该看到任何问题。

  • 取决于DEBUG常量的框架代码的一个示例是Debug.Assert()方法,该方法具有定义属性[Conditional("DEBUG)"] 。 这意味着它也依赖于DEBUG常量,这不包含在发布版本中。


    这在很大程度上取决于应用程序的性质。 如果您的应用程序的UI很重,您可能不会注意到任何差异,因为连接到现代计算机的最慢组件是用户。 如果您使用某些UI动画,则可能需要测试在DEBUG构建中运行时是否可以察觉到任何明显的滞后。

    但是,如果你有很多计算繁重的计算,那么你会注意到差异(可能高达@ @ @皮特提到的40%,尽管它取决于计算的性质)。

    这基本上是一个设计权衡。 如果您在DEBUG版本下发布,那么如果用户遇到问题,则可以获得更有意义的回溯,并且可以执行更灵活的诊断。 通过在DEBUG版本中发布,您还可以避免优化器产生晦涩的Heisenbugs。

    链接地址: http://www.djcxy.com/p/14147.html

    上一篇: Performance differences between debug and release builds

    下一篇: Why isn't this F# code tail