oo_*_*_oo 53 c++ embedded exception-handling exception footprint
这个问题对于嵌入式开发尤为重要.异常处理为生成的二进制输出增加了一些空间.另一方面,没有例外,错误需要以其他方式处理,这需要额外的代码,这最终也会增加二进制大小.
我对你的经历很感兴趣,特别是:
请仅以我的问题为指导.欢迎任何输入.
附录:对于特定的C++对象/可执行文件,是否有任何人具有具体的方法/脚本/工具,它将显示由编译器生成的代码和专用于异常处理的数据结构占用的已加载内存占用的百分比?
bia*_*ias 35
发生异常时,会产生时间开销,具体取决于您实现异常处理的方式.但是,作为轶事,应该导致异常的事件的严重性将花费同样多的时间来处理使用任何其他方法.为什么不使用高度支持的基于语言的方法来处理这些问题呢?
GNU C++编译器默认使用零成本模型,即在不发生异常时没有时间开销.
由于有关异常处理代码和本地对象偏移的信息可以在编译时计算一次,因此这些信息可以保存在与每个函数关联的单个位置,但不能保存在每个ARI中.您基本上可以从每个ARI中删除异常开销,从而避免将额外时间推送到堆栈上.这种方法称为异常处理的零成本模型,前面提到的优化存储称为影子堆栈. - Bruce Eckel,思考C++第2卷
规模复杂性开销不容易量化,但Eckel平均表示5%和15%.这取决于异常处理代码的大小与应用程序代码大小的比率.如果你的程序很小,那么异常将是二进制文件的很大一部分.如果您使用零成本模型而不是异常会占用更多空间来消除时间开销,因此如果您关心空间而不是时间而不是使用零成本编译.
我的观点是,大多数嵌入式系统都有足够的内存,如果你的系统有一个C++编译器,你有足够的空间来包含异常.我项目使用的PC/104计算机有几GB的二级存储器,512 MB的主存储器,因此没有空间问题 - 但是,我们的微控制器是用C编程的.我的启发式是"如果有一个主流的C++编译器它,使用例外,否则使用C".
小智 20
测量的东西,第2部分.我现在有两个程序.第一个是在C中,用gcc -O2编译:
#include <stdio.h>
#include <time.h>
#define BIG 1000000
int f( int n ) {
int r = 0, i = 0;
for ( i = 0; i < 1000; i++ ) {
r += i;
if ( n == BIG - 1 ) {
return -1;
}
}
return r;
}
int main() {
clock_t start = clock();
int i = 0, z = 0;
for ( i = 0; i < BIG; i++ ) {
if ( (z = f(i)) == -1 ) {
break;
}
}
double t = (double)(clock() - start) / CLOCKS_PER_SEC;
printf( "%f\n", t );
printf( "%d\n", z );
}
Run Code Online (Sandbox Code Playgroud)
第二个是C++,带有异常处理,用g ++ -O2编译:
#include <stdio.h>
#include <time.h>
#define BIG 1000000
int f( int n ) {
int r = 0, i = 0;
for ( i = 0; i < 1000; i++ ) {
r += i;
if ( n == BIG - 1 ) {
throw -1;
}
}
return r;
}
int main() {
clock_t start = clock();
int i = 0, z = 0;
for ( i = 0; i < BIG; i++ ) {
try {
z += f(i);
}
catch( ... ) {
break;
}
}
double t = (double)(clock() - start) / CLOCKS_PER_SEC;
printf( "%f\n", t );
printf( "%d\n", z );
}
Run Code Online (Sandbox Code Playgroud)
我认为这些回答了我上一篇文章的所有批评.
结果:执行时间使C版本比C++版本具有0.5%的优势,但不是其他人已经谈过的10%(但没有演示)
我会非常感激,如果其他人可以尝试编译和运行代码才能(只需要几分钟的时间)来检查,我还没有做出可怕的和明显的错误在任何地方.这被称为"科学方法"!
我在低延迟环境中工作.(对于我在"生产链"中的应用而言,300微秒以下)根据我的经验,异常处理会增加5-25%的执行时间,具体取决于您的工作量!
我们一般不关心二元臃肿,但是如果你得到太多臃肿然后你就像疯了一样捶打,所以你需要小心.
只需保持二进制文件合理(取决于您的设置).
我对我的系统进行了大量的分析.
其他令人讨厌的地区:
记录
坚持(我们只是不做这个,或者如果我们这样做的话)
我想这取决于该特定平台的硬件和工具链端口。
我没有数字。然而,对于大多数嵌入式开发,我看到人们放弃了两件事(对于 VxWorks/GCC 工具链):
在大多数情况下,异常处理确实同时使用了两者,因此也有将其丢弃的趋势。
在那些我们真的想接近金属的情况下,使用setjmp/ longjmp。请注意,这可能不是最好的解决方案(或非常强大),但这就是 _we_ 使用的。
您可以使用带有/不带异常处理的两个版本的基准测试套件在您的桌面上运行简单的测试,并获取您最依赖的数据。
关于嵌入式开发的另一件事:模板就像瘟疫一样被避免——它们会导致过多的膨胀。正如 Johann Gerell 在评论中所解释的那样,沿着模板和 RTTI 标记异常(我认为这很好理解)。
同样,这正是我们所做的。所有的downvoting是什么?