使用附加到进程的CLR调试器,.NET代码运行速度会变慢吗?

几乎所谓的标题:我正在运行一个很长的程序,它附加了CLR调试器,所以我可以捕获并检查exception。 我是否在没有调试器的情况下获得与运行它相当的性能,或者我付出了严重的(2-10倍或更多)惩罚?

最重要的:工具+选项,调试,通用,抑制模块负载的JIT优化。 如果你想调试发布代码并获得可比较的性能,你希望这样做。 但这确实使得调试代码变得更加困难,JIT优化器会将本地变量存储在CPU寄存器中(Watch将无法工作)并重新排序和内联代码(步进行为很奇怪)。

然后是DebuggableAttribute,由编译器自动生成。 它的IsJITOptimizerEnabled和IsJITTrackingEnabled属性很重要。 首先,它们可以使局部变量保持活动状态只需要比所需时间长一点,从而防止垃圾收集器收集您可能希望在调试器中检查的引用。 容易避免,只需调试Release版本而不是Debug版本。

然后在您的程序中发生特定的事情,唤醒调试器并使其窃取CPU周期:

  • 当你的程序抛出exception时。 调试器在抛出之前会对它进行一次射击。 称为“第一次机会通知”,您可以在“输出”窗口中看到它。 这就是Debug + Exceptions对话框的工作原理。 减慢exception处理速度很慢。
  • 当您的程序加载或卸载DLL时。 在加载时发生了很多事情,调试器试图找到DLL的符号。 检查是否需要激活任何断点。 并在“输出”窗口中显示通知。 这通常只会使程序启动变慢,尤其是在打开混合模式调试时。
  • 当您使用Trace类与DefaultTraceListener,Debug.Write / Line()方法或Console.Write / Line并启用托管进程时。 输出显示在“输出”窗口中,会大大减慢这些调用的速度。
  • 当程序中的某个线程启动或停止时。 在“输出”窗口中可见。 让它减慢你的程序将是一个设计错误。

就是这样,只要不执行上面列出的操作,调试器就会停止运行并让代码全速运行。 像ASP.NET和Silverlight这样的运行时环境很特殊,可能还有额外的开销。 在64位操作系统上调试Any CPU程序也是如此,这需要远程调试器,因为VS仅为32位。

我看到了相当大的差异,是的。

特别是,当抛出exception时,在附加调试器时需要花费更长的时间。 还有一些其他重要的优化会影响行为 – 例如,当未附加调试器时,垃圾收集器会更加激进。

为什么不记录exception而不是闯入调试器? 除了其他任何东西,这意味着如果你想回去查看昨天发生的exception并将其与刚刚发生的exception进行比较,这很容易……回到过去很难回事:)

附加调试器会禁用一些JIT优化 – 例如函数内联。

http://msdn.microsoft.com/en-us/library/bb384548.aspx

你的表现可能会更差。