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

时间:2010-10-28 14:23:56

标签: c# .net performance debugging configuration

我必须承认,通常我没有打扰在我的程序中的 Debug Release 配置之间切换,我通常选择去调试配置,即使程序实际部署在客户所在地也是如此。

据我所知,如果不手动更改,这些配置之间的唯一区别是 Debug 定义了 DEBUG 常量,和发布已选中优化代码

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

  1. 这两种配置之间是否存在很多性能差异。是否有任何特定类型的代码会在这里造成性能上的巨大差异,或者它实际上并不重要?

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

8 个答案:

答案 0 :(得分:502)

C#编译器本身并不会在Release版本中大量改变发出的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抖动中是一个大问题,因为它几乎没有寄存器可供使用。让它选择正确的对于perf来说至关重要。

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

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

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

答案 1 :(得分:23)

  1. 是的,存在许多性能差异,这些差异确实适用于您的所有代码。 Debug非常少地进行性能优化和发布模式;

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

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

答案 2 :(得分:12)

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

但是,如果你有许多计算量很大的计算,那么你会注意到差异(可能会高达40%,正如@Pieter所提到的,尽管这取决于计算的性质)。

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

答案 3 :(得分:11)

  • 我的经验是,在发布版本中,中型或大型应用程序的响应速度明显提高。尝试使用您的应用程序,看看它的感受。

  • 使用Release版本可以咬你的一件事是,Debug构建代码有时可以抑制竞争条件和其他与线程相关的错误。优化的代码可能导致指令重新排序,更快的执行会加剧某些竞争条件。

答案 4 :(得分:9)

您永远不应该将.NET Debug版本发布到生产环境中。它可能包含难看的代码以支持编辑并继续,或者谁知道还有什么。据我所知,这种情况只发生在VB而不是C#(注意:原始帖子标记为C#),但它仍然应该暂停微软认为允许他们做什么一个Debug构建。事实上,在.NET 4.0之前,VB代码会泄漏内存,这些内存与您构建的支持Edit-and-Continue的事件的对象实例数成正比。 (虽然据报道这是根据https://connect.microsoft.com/VisualStudio/feedback/details/481671/vb-classes-with-events-are-not-garbage-collected-when-debugging修复的,生成的代码看起来很讨厌,创建WeakReference个对象并将它们添加到静态列表中,而持有锁)我当然不喜欢在生产环境中不希望任何这种调试支持!

答案 5 :(得分:5)

根据我的经验,发布模式中最糟糕的事情是模糊的“发布错误”。由于IL(中间语言)在发布模式下进行了优化,因此存在错误的可能性,这些错误在调试模式下不会出现。还有其他SO问题涉及此问题: Common reasons for bugs in release version not present in debug mode

这种情况发生在我身上一两次,一个简单的控制台应用程序在调试模式下运行完全正常,但是如果输入完全相同,则会在发布模式下出错。这些错误非常难以调试(根据发布模式的定义,具有讽刺意味)。

答案 6 :(得分:3)

我会说1)在很大程度上取决于你的实施。通常情况下,差异并不大。我做了很多测量,经常看不出差异。如果你使用非托管代码,许多大型数组和类似的东西,性能差异稍大,但不是一个不同的世界(如在C ++中)。 2)通常在发布代码中显示更少的错误(更高的容差),因此开关应该正常工作。

答案 7 :(得分:0)

    **Debug Mode:**
    Developer use debug mode for debugging the web application on live/local server. Debug mode allow developers to break the execution of program using interrupt 3 and step through the code. Debug mode has below features:
   1) Less optimized code
   2) Some additional instructions are added to enable the developer to set a breakpoint on every source code line.
   3) More memory is used by the source code at runtime.
   4) Scripts & images downloaded by webresource.axd are not cached.
   5) It has big size, and runs slower.

    **Release Mode:**
    Developer use release mode for final deployment of source code on live server. Release mode dlls contain optimized code and it is for customers. Release mode has below features:
    More optimized code
    Some additional instructions are removed and developer can’t set a breakpoint on every source code line.
   1) Less memory is used by the source code at runtime.
   2) Scripts & images downloaded by webresource.axd are cached.
   3) It has small size, and runs fast.
   4) Scripts & images downloaded by webresource.axd are cached.
   5) It has small size, and runs fast.