为什么在CLR中,空引用异常比其他任何异常都更昂贵?

8
在寻找空值检查与捕获NullReferenceException的区别时,我发现了这篇文章。
捕获null引用是CLR执行的最昂贵的操作之一,如果您的代码经常抛出NullReferenceExceptions,则可能会对性能产生严重影响。测试空值并采取其他措施(甚至抛出异常!)是更便宜的操作。
这里是我找到的问题链接:当处理空指针引用异常优于进行空检查时? 我想知道如何捕获NullReferenceException比空检查和抛出异常更昂贵。[因为声望不足,无法在那里发表评论]
2个回答

9

这里的重点不在于NullReferenceException比其他异常更昂贵。抛出异常的成本来自于展开堆栈,这更取决于调用结构而不是具体的异常。我相信文档试图说明的是,与其在抛出异常时进行处理,预先防范异常的成本更低。


2
< p > 一个 NullReferenceException 是一种 硬件异常,它首先由 Windows 页面错误处理程序处理。这个操作需要一个 内核上下文切换,这可能是一个非常昂贵的操作,取决于底层 CPU 硬件和操作系统安全模型。此外,垃圾回收器通常必须暂停某些操作,直到上下文切换完成。由于 GC 服务于所有线程和应用程序域,GC 在暂停中花费的任何时间都可能导致潜在的性能损失,这些性能损失只会在意想不到的间隔期间表现出来。

相比之下,通过 C# 中的 throw 关键字从自己内部抛出异常会生成一个 软件异常。这些不需要特殊处理,在异常的 catch 处理程序是本地的情况下(在同一个函数内),还可以进一步优化,因为不需要额外的展开来发现适当的 catch 处理程序。这就是为什么 MSDN 文档建议不要依赖于 NullReferenceException 的原因。

很难给出性能差异的具体值,因为有这么多的变量在发挥作用。在最坏的情况下,我可以想象它可能会慢近一个数量级——例如,在处理单个硬件异常的时间内,可以抛出和捕获大约一百个本地软件异常。不过实际上,我猜测性能比是在 3:1 到 10:1 左右,这取决于 CPU、操作系统、C# CLR 和共享 Heap/GC 的活动线程数量。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接