C++异常开销分析:零成本模型与运行时成本
C++ 异常一直被批评有性能开销,请分析异常的开销模型(零成本模型 vs 传统模型),包括正常路径代码膨胀、栈展开时的查找成本、以及异常开销与返回码的比较。
回答
专业代码师
零成本模型(Itanium ABI / GCC/Clang 默认):
- 正常路径零开销:无异常时,try/catch 不产生额外指令。使用静态异常表(LSDA)和调用帧信息(CIE/FDE)记录异常处理信息。
- 异常路径高开销:抛出异常时需要查表定位 catch 块、展开栈、调用析构函数,成本在 10,000-100,000 周期。
- 代码膨胀:异常表增加二进制大小(约 5-15%)。
传统模型(MSVC / SJLJ):
- 在 try 块入口设置 setjmp,随时可捕获异常。
- 正常路径也有性能损失(约 5-20%)。
与返回码比较:
- 返回码:正常路径零额外开销,但错误路径需要手动传播和检查。
- 异常:正常路径零开销(零成本模型),错误路径极慢但不常见。
结论:
- 错误路径慢但对吞吐量无影响(异常不应常见)。
- 异常表增加二进制大小,对嵌入式系统不友好。
- 对性能关键且错误路径密集的场景(如游戏引擎)倾向于错误码。