D中异常处理的开销

11
在D2编程语言中,使用异常处理会有哪些性能影响?特别是:
  • 如果我没有编写异常处理代码会怎样?
  • 如果我编写了异常处理代码,但从未出现过异常会怎样?
  • 如果我编写了异常处理代码,并且出现了异常会怎样?
  • 异常处理是否会导致错过任何优化机会?
  • 是否可以像许多(大多数?)C++实现那样禁用异常处理?
我知道几乎所有商业游戏开发工作室都会禁用C ++中的异常处理,因为正确处理异常涉及到的性能影响和增加的开发时间。我知道 D 使得后者不那么痛苦,但性能如何呢?
当然,这可能都是实现定义的,因此对于此问题,请集中关注 DMD 编译器。
2个回答

27

我不能谈论 D 或其任何编译器,但我可以告诉您一些关于 C++、Windows 和 Visual Studio 编译器的信息。这可能有助于您大致了解 D 是如何工作的。

首先,32 位和 64 位机器上的异常处理方式是不同的。x86 ABI(过程前奏/后奏、展开、调用约定)更加松散,因此编译器和程序本身必须做更多的工作。x86-64 ABI 更严格,操作系统发挥更大的作用,使程序自身更容易处理异常。如果您在 Windows 上运行 D,则它很可能像 C++ 一样使用 SEH(结构化异常处理)。

再次强调,以下所有回答都与 Windows、C++ 和 Visual Studio 相关。

如果我没有编写异常处理代码呢?

x86/x86-64:该方法没有成本。

如果我编写了异常处理代码,但从未抛出异常呢?

x86:即使没有抛出异常,该方法也会产生成本。异常处理信息被推入 TIB(线程信息块),例如初始范围和特定于函数的异常处理程序。为了知道要析构哪些对象和搜索哪些处理程序,需要维护一个作用域变量。随着进入 try 块并构造具有析构函数的堆栈对象,该作用域变量将被更新。

x86-64:由于规则更严格,因此没有额外的代码(或非常非常少)。这是相对 x86 的一个很大优势。

如果我编写了异常处理代码,并且抛出了异常呢?

无论在x86还是x86-64上,抛出异常都会有一定的开销。不过,异常应该是例外而非常规控制流程。只有在真正意外的情况下才使用它们。基本上,您永远不必担心异常的成本。即使它们需要2秒钟,您也不用担心,因为它们只会在一切都出现问题的情况下发生。 话虽如此,在x86-64上抛出异常比在x86上抛出异常更昂贵。x86-64架构针对没有抛出异常的情况进行了优化,理想情况下,这几乎是所有时间。
总体而言:
  • 我看不出传播错误代码比异常处理更快,尤其是在x64平台上。
  • 我怀疑除非您滥用异常,否则您永远不会发现异常处理成为问题。
  • 如果您不确定,您应该测量代码的性能。

1
对于一般情况,这是一个很好的回应。我还想说,如果编写异常处理代码会减慢开发速度,那么之前你的开发速度太快了;如果“几乎所有”工作室都禁用异常处理,那么他们就是在自己给自己挖坑。可以说,大型项目比小型项目更有利于使用异常处理代码。事实上,我想到了《辐射3》在发布时,似乎该游戏大量使用了异常处理,但不幸的是,他们没有处理所有的异常。 - Tim
嗨,Chris!你能推荐一本详细描述这个问题的书吗? - D_E
@D_E:不幸的是,编译器实现有点神秘,异常处理更是如此(因为它涉及操作系统、语言、运行时和编译器)。我的知识来自于在微软性能分析团队的工作。我建议你在网上搜索,因为我认为那将是你最好的选择。 - Chris Schmich
1
x86/x86-64:这种方法没有任何成本。鉴于更大的代码大小和较少的优化机会,你真的能这么说吗? - John McFarlane

6
据我所知,DMD使用平台本身的机制。在Windows上,这将是结构化异常处理,这也是MSVC ++用于实现异常的方式。
在Linux上,我认为它使用与GCC相同的异常表机制。在其他平台上,我不清楚。
从性能上来看,它可能与C ++相同(或者至少非常接近)。

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