.net 为什么抛出异常这么慢?

.net 为什么抛出异常这么慢?,.net,performance,exception,internals,.net,Performance,Exception,Internals,他们告诉我们不要使用异常来控制程序流,因为抛出异常的速度很慢。我从未听过任何解释为什么抛出异常如此缓慢 因此,问题是: 抛出异常的机制是什么?涉及哪些可能影响性能的特定操作 编辑: 一些澄清:我想听听操作系统需要做哪些额外的工作来处理抛出异常。在用户模式和内核模式之间是否存在一些代价高昂的切换?或者构造异常对象的成本很高?或者,可能有一些与切换程序流我错过了什么?我的问题是编程语言不可知论(我希望如此,但证明我错了)。然而,如果您需要一些锚,那么我最感兴趣的是与本主题相关的.NET内部构件 编辑

他们告诉我们不要使用异常来控制程序流,因为抛出异常的速度很慢。我从未听过任何解释为什么抛出异常如此缓慢

因此,问题是:

抛出异常的机制是什么?涉及哪些可能影响性能的特定操作

编辑:

一些澄清:我想听听操作系统需要做哪些额外的工作来处理抛出异常。在用户模式和内核模式之间是否存在一些代价高昂的切换?或者构造异常对象的成本很高?或者,可能有一些与切换程序流我错过了什么?我的问题是编程语言不可知论(我希望如此,但证明我错了)。然而,如果您需要一些锚,那么我最感兴趣的是与本主题相关的.NET内部构件

编辑2:

我没有任何关于性能异常的问题。我只想了解这个机制的内部结构

编辑3:


使我的问题更清楚。

异常是在应用程序级别创建的;他们没有操作系统支持。没有特别的原因说明抛出和捕获异常应该比任何其他非本地控制传输(如调用函数或从函数返回)慢


是什么使异常比返回错误代码的替代方法“慢”取决于编程环境的细节所需的额外工作。例如,在Java中,抛出异常最慢的部分是填充堆栈跟踪。

异常处理需要一些复杂性和“魔力”。支持@Joni的响应一个主要成本是收集堆栈跟踪。当抛出异常时,运行时必须遍历堆栈的激活记录,寻找兼容的异常处理程序,最后执行会阻塞该过程中的每个步骤。所有这些都必须在运行时发生;编译器无法修复它。在C++语言中,必须执行析构函数。
异常处理本质上是带外“异常”处理模式。加速正常执行的东西(如缓存)也不能正常工作。(我认为这里的引用位置要糟糕得多)。此处理可以优化,但由于exc处理被认为是“特殊的”,因此很少受到关注。

将异常用于流控制是个坏主意的主要原因是我应该能够附加一个调试器,并告诉它在异常时中断。。。在特殊情况下它会断裂。如果代码使用异常进行流控制,并且在正常操作下经常中断,那么在没有异常的情况下调试就变得非常困难。。。但也许你最终错过了一个真正的例外情况

如果我编写了验证积极功能的测试,我应该能够在附加了调试器的情况下运行它们,而调试器不会捕获。如果你不能做到这一点,你可能会滥用异常


举个例子:假设我有代码来获取一个id为的项目。我的代码最终发现该id为的项目不存在。我应该抛出NotFoundException吗?这是一个争论点——我想说不——这里没有发生任何异常/错误。您的代码没有正确地发现存在该id的任何内容,也没有发现该id的错误。在这些情况下,我看到异常被滥用,并导致在非异常情况下抛出异常。

您收到了错误信息,但实际代码的结果可能不会以任何方式改变。NET中的异常处理系统实际上相当快,这意味着它的性能与其他错误处理选项相当。但是,正如在另一个答案中提到的,您只希望适当地使用异常,即仅适用于在应用程序正常运行期间不希望发生的异常情况。原因如下:

  • 分析包含异常的代码流比不包含异常的代码更复杂,所以“正常”代码应该避免抛出异常
  • Visual Studio调试器将在每次引发异常时报告。输出窗口中只有一行,但是如果您误用了异常,那么这个奇妙的特性将很快变成一场噩梦
  • Visual Studio能够在引发特定类型的异常时中断。如果您始终正确地使用异常(出于预期目的,并且仅用于指示该类型的实际异常),则此功能提供了一种快速调试应用程序中与错误处理(恢复、报告等)相关的错误的方法

当涉及到处理实际异常情况时,异常处理实际上比返回错误代码等其他事情提供了性能优势。当涉及到分支预测和暗示时,JIT可以假设代码永远不会抛出异常,允许它生成有效使用处理器的任何可用分支预测功能的代码,以避免包含错误处理功能但未主动处理错误的代码的分支开销。

您所指的是哪种语言的实现,谁说它的异常处理很慢?我指的是一般情况下抛出异常,我想每个人都在说:我的学术老师,我的同事,我的老板,互联网上的每个人:)可能的重复如果你因为异常而出现性能问题,不仅仅是异常很慢,这是因为你扔的太多了。换句话说,如果您正确地使用异常来指示异常问题,那么您就不必费心了。一个常见的说法是:如果您关心异常性能,那么您可能过度使用了异常。然而,性能仍然是一个很好的讨论话题。最后,块和析构函数并没有起到作用