同一函数中的异常处理会使编译时间减慢 2 倍以上,为啥?

Posted

技术标签:

【中文标题】同一函数中的异常处理会使编译时间减慢 2 倍以上,为啥?【英文标题】:Exception handling in the same function slows compile times by > 2x, why?同一函数中的异常处理会使编译时间减慢 2 倍以上,为什么? 【发布时间】:2014-07-21 00:24:14 【问题描述】:

我有一个数千行的项目,其中包含一个巨大的 main(约 800 行)。 包含 main 函数的文件编译需要 7.94 秒。

代码结构如下:

int main(int argc, char *argv[])

    int result = 0;
    try
    
        /* 800 lines of code here */
    
    catch (std::invalid_argument const &ex)
    
        std::cerr << ex.what() << std::endl;
        return EINVAL;
    
    catch (std::runtime_error const &ex)
    
        std::cerr << ex.what() << std::endl;
        return -1;
    
    return 0;

但是,当我将其更改为

void run(int argc, char *argv[])

    /* 800 lines of code here */


int main(int argc, char *argv[])

    int result = 0;
    try
    
        run(argc, argv);
    
    catch (std::invalid_argument const &ex)
    
        std::cerr << ex.what() << std::endl;
        return EINVAL;
    
    catch (std::runtime_error const &ex)
    
        std::cerr << ex.what() << std::endl;
        return -1;
    
    return 0;

编译时间减少到 2.48 秒!

我可以说罪魁祸首是异常处理代码,因为当我删除周围的 try/catch 时,我得到了同样的编译时间减少。

此外,如果我将run 函数标记为__forceinline,编译时间增加到10.02!但是如果我在取出try/catch 之后再这样做,那么它会下降到仅仅 3.27 秒。

但是什么给了?当代码直接位于 try 块的主体内时,编译器究竟需要做什么才能使计算量变得如此之多?

注意事项:

我正在 RELEASE 模式下编译 Microsoft Visual C++ Nov 2013 CTP 编译器(原生 x64) 相关编译器选项:/O2 /Gm- /GS /EHsc(删除 /EHsc 也可以加快编译速度)

【问题讨论】:

我认为除了编译器设计者之外没有人可以回答为什么这个问题。编译器可能非常复杂,并且很容易从看似不相关的设计决策中触发意想不到的后果。编译器的主要工作是正确;性能是次要考虑因素。请注意,我并不是说在这种情况下确保正确性需要额外的时间。我不知道它在做什么,而且微软编译器团队之外的其他人也不太可能这样做。 你试过其他编译器吗? 我对 try/catch 的开销并不感到惊讶,但让我感到惊讶的是,这两个代码之间的性能差异! @Samer:不,我没有尝试在其他编译器上测量时间。如果我得到更多数据,我会发布更新。 @GregHewgill:我希望也许有更多编译器经验的人可以做出有根据的猜测。 【参考方案1】:

我怀疑差异与额外的清理代码有关。在函数中声明的 C++ 对象在离开时会被销毁,因此它们的销毁代码已经在函数结尾处,并且(我认为)堆栈展开(异常处理过程的一部分)可以使用该代码。如果您需要在离开函数的情况下销毁所有这些对象 - 需要生成和管理额外的销毁代码,这会影响构建时间和二进制大小。你能说二进制大小是否有差异吗?

尽管坦率地说,我很惊讶这两种影响(时间/大小)都是可测量的。 “800 行”在 C++ 对象创建方面是否异常丰富? (也许是间接的)

【讨论】:

以上是关于同一函数中的异常处理会使编译时间减慢 2 倍以上,为啥?的主要内容,如果未能解决你的问题,请参考以下文章

java 异常不处理会怎么样

如何处理会话超时异常(使用 MVP 地点和活动)?

使用 Pyglet 进行多处理会打开一个新窗口

alijdk 8.1.1的优化使ssl性能提升2倍以上

过滤器如何处理会话

在 Python 中使用 Pool 类进行多处理会产生 Pickling 错误