繁体   English   中英

C++ 异常开销

[英]C++ exception overhead

为什么嵌入式平台开发人员不断尝试从他们的SDKs中删除使用C++ exceptions

例如, Bada SDK为异常使用建议了以下变通方法,看起来异常难看:

 result
 MyApp::InitTimer()
 {
    result r = E_SUCCESS;

    _pTimer = new Timer;

    r = _pTimer->Construct(*this);
    if (IsFailed(r))
    {
        goto CATCH;
    }

    _pTimer->Start(1000);
    if (IsFailed(r))
    {
        goto CATCH;
    }

    return r;
 CATCH:
     return r;
 }

这种行为的原因是什么?

据我所知, ARM编译器完全支持C++ exceptions ,这实际上不是问题。 还有什么? ARM平台上的异常使用和展开的开销真的要花很多时间做这样的变通方法吗?

也许还有其他我不知道的东西?

谢谢你。

只是我的2美分...

我专门咨询嵌入式系统,其中大多数是硬实时和/或安全/生命攸关的。 它们中的大多数运行在 256K 或更少的闪存/ROM 中 - 换句话说,这些不是具有 1GB+ RAM/闪存和 1GHz+ CPU 的“类似 PC”的 VME 总线系统。 它们是深度嵌入、资源有限的系统。

我想说至少 75% 的使用 C++ 的产品在编译器中禁用异常(即,使用禁用异常的编译器开关编译的代码)。 我总是问为什么。 信不信由你,最常见的答案不是运行时或 memory 开销/成本。

答案通常是以下几种:

  • “我们不确定我们知道如何编写异常安全代码”。 对他们来说,检查返回值更熟悉、更简单、更安全。
  • “假设你只在特殊情况下抛出异常,这些情况下我们无论如何都要重启 [通过他们自己的严重错误处理程序例程]”
  • 遗留代码问题(正如 jalf 所提到的) - 他们正在使用多年前开始的代码,当时他们的编译器不支持异常,或者没有正确或有效地实现它们

此外 - 经常有一些关于开销的模糊不确定性/恐惧,但几乎总是它是未量化/未分析的,它只是一种被扔在那里并按面值计算。 我可以向您展示 state 的报告/文章,异常开销为 3%、10%-15% 或 ~30% - 任您选择。 人们倾向于引用代表自己观点的人物。 几乎总是,文章已经过时,平台/工具集完全不同,等等。正如罗迪所说,你必须在你的平台上衡量自己。

我不一定要为这些立场辩护,我只是给你真实的反馈/解释,我从许多与 C++ 在嵌入式系统上合作的公司那里听到,因为你的问题是“为什么这么多嵌入式开发人员避免例外?”

我能想到几个可能的原因:

  • 旧版本的编译器不支持异常,因此编写了很多代码(并建立了约定),其中不使用异常
  • 异常确实是有代价的,它可能占总执行时间的 10-15%(它们也可以实现为几乎不花时间,但使用相当多的 memory 代替,这可能不是很理想在嵌入式系统上)
  • 嵌入式程序员往往对代码大小、性能,尤其是代码复杂性有点偏执。 他们经常担心“高级”功能可能无法在他们的编译器中正常工作(而且他们通常也是正确的)

我认为这主要是 FUD,这些天。

异常确实在创建具有构造函数/析构函数的对象的块的入口和出口处有少量开销,但在大多数情况下,这实际上不应该相当于一罐豆子。

先测量,再优化。

但是,抛出异常通常比仅返回 boolean 标志要慢,因此仅针对异常事件抛出异常

在一种情况下,我看到 RTL 正在从符号表构造整个可打印的堆栈跟踪,只要抛出异常以供潜在的调试使用。 可以想象,这不是一件好事 这是几年前的事了,当这个问题曝光时,调试库被匆忙修复。

但是,IMO,您从正确使用异常中获得的可靠性远远超过了轻微的性能损失。 使用它们,但要小心。

编辑:

@jalf 提出了一些很好的观点,我上面的回答针对的是为什么许多嵌入式开发人员通常仍然贬低例外的相关问题。

但是,如果特定平台 SDK 的开发人员说“不要使用异常”,那么您可能不得不使用 go。 也许他们的库或编译器中的异常实现存在特殊问题 - 或者他们担心回调中抛出的异常会由于他们自己的代码中缺乏异常安全性而导致问题。

这种对异常的态度与性能或编译器支持无关,而是与异常增加代码复杂性的想法有关。

据我所知,这个想法几乎总是一种误解,但由于某些不可思议的原因,它似乎有 强大的支持者

与其他答案所支持的“gotos are evil”相反的观点。 我正在制作这个社区维基,因为我知道这种相反的观点会被激怒。

任何称职的实时程序员都知道goto的这种用法。 它是一种广泛使用且被广泛接受的错误处理机制。 许多硬实时编程环境没有实现<setjmp.h>。 例外在概念上只是setjmplongjmp的受限版本。 那么,当底层机制被禁止时,为什么要提供异常呢?

如果始终可以保证在本地处理所有抛出的异常,则环境可能允许异常。 问题是,为什么要这样做? 唯一的理由是 gotos 总是邪恶的。 好吧,他们并不总是邪恶的。

现代 C++ 编译器可以将异常的运行时使用率降低到低至 3% 的开销。 尽管如此,如果极端程序员发现它很昂贵,那么他们就会诉诸这种肮脏的伎俩。

请参阅此处 Bjarne Strourstrup 的页面,了解为什么使用异常?

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM