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

标签 c# .net performance debugging configuration

我必须承认,通常我不会在我的程序中的 Debug 和 Release 配置之间切换,而且我通常选择去 Debug 配置,即使程序实际部署在客户处也是如此。

据我所知,如果不手动更改,这些配置之间的唯一区别是 Debug 具有 DEBUG 常量已定义,Release 已检查优化代码。

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

  • 这两种配置之间是否有很大的性能差异。是否有任何特定类型的代码会导致这里的性能出现巨大差异,或者它实际上并不那么重要?
  • 是否有任何类型的代码可以在 Debug 配置下正常运行而在 Release 配置下可能会失败,或者您能否确定在 Debug 配置下测试并正常工作的代码在 Release 配置下也能正常工作。
  • 最佳答案

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

  • 方法内联。方法调用被注入(inject)方法的代码所取代。这是一个很大的问题,它使属性访问器基本上免费。
  • 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 = 一个; y = x;变成 y = a;这有助于寄存器分配器做出更好的决策。这是 x86 抖动中的一个大问题,因为它几乎没有可用的寄存器。让它选择正确的对性能至关重要。

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

    这些优化对程序执行时间的有效结果通常会受到在别处运行的代码的影响。读取文件、执行 dbase 查询等。使 JIT 优化器所做的工作完全不可见。不过没关系:)

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

    关于c# - 调试版本和发布版本之间的性能差异,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/4043821/

    相关文章:

    sql - EXEC sp_executesql 与 INSERT INTO :( 一起使用时非常慢

    c# - 将逐个元素添加到 ListView 而不阻塞 UI

    c# - UserManager.CreateAsync 挂起从单元测试而不是 Postman 执行

    python - 为什么单循环函数比双循环慢?

    c# - 使用其中的代码创建 mustoveride 函数

    c# - 命名空间 'Documents' 中不存在类型或命名空间名称 'System.Windows'

    mysql - 请推荐Ubuntu/Debian下MySQL的性能测试工具

    c# - VSTest 只运行一种类型的测试

    c# - 如何在 .NET 应用程序中隐藏加密 key ?

    c# - 我如何优化这个像素不透明度计算?