异常处理的系统开销

 
为了运行时处理异常,程序要记录大量的信息。无论执行到什么地方,程序都必须能识别出若在此处抛出异常,将要被释放哪一个对象;程序必须知道每一个入口点,以便从try块中退出;对于每一个try块,它们都必须跟踪与其相关的catch子句以及这些catch子句能够捕获的异常类型。这种信息的记录不是没有代价的。确保程序满足异常规格不需要运行时的比较(runtime comparisons),而且当异常被抛出时也不用额外的开销来释放相关的对象和匹配正确的catch字句。但是异常处理确是有代价的,即使没有使用try,throw或catch关键字,同样得付出一些代价。

    先从不使用任何异常处理特性也要付出的代价谈起。需要空间建立数据结构来跟踪对象是否被完全构造(constructed),也需要系统时间保持这些数据结构不断更新。这些开销一般不是很大,但是当采用不支持异常的方法编译的程序一般比支持异常的程序运行速度更快,所占空间也更小。

  在理论上,不能对此进行选择:C++编译器必须支持异常,也就是说,当不用异常处理时不能让编译器生产商消除这方面的开销,因为程序一般由多个独立生成的目标文件(object file-s)组成,只有一个目标文件不进行异常处理并不能代表其他目标文件不进行异常处理。而且即使组成可执行文件的目标文件都不进行异常处理,那么还有它们所连接的程序库.如果程序的任何部分使用了异常,其它部分必须也支持异常。否则在运行时程序就不可能提供正确的异常处理。

  不过这只是理论,实际上大部分支持异常的编译器生产商都允许自由控制是否在生成的代码里包含进支持异常的内容。如果知道程序的任何部分都不使用try,throw或catch,并且也知道所连接的程序库也没有使用try,throw或catch,就可以采用不支持异常处理的方法进行编译,这可以缩小程序的尺寸和提高速度,否则就得为一个不需要的特性而付出代价。随着时间的推移,使用异处理的程序库开始变得普遍了,上面这种方法将逐渐不能使用,但是根据目前的软件开发情况来看,如果已经决定不使用任何的异常特性,那么采用不支持异常的方法编译程序是一个性能优化的合理方法。同样这对于想避开异常的程序库来说也是一个性能优化的好方法,这能保证异常不会从客户端程序传递进程序库里,不过同时这样做也会妨碍客户端程序重定义程序库中声明的虚拟函数,并不允许有在客户端定义的回调函数。

  使用异常处理的第二个开销来自于try块,无论何时使用它,也就是无论何时想能够捕获异常,那都得为此付出代价。不同的编译器实现try块的方法不同,所以编译器与编译器间的开销也不一样。粗略地估计,如果使用try块,代码的尺寸将增加5%-10%并且运行速度也同比例减慢。这还是假设程序没有抛出异常,这里讨论的只是在程序里使用try块的开销。为了减少开销,应避免使用无用的try块。

  编译器为异常规格生成的代码与它们为try块生成的代码一样多,所以一个异常规格一般花掉与try块一样多的系统开销。( 异常规格使得代码更容易理解,因为它明确地描述了一个函数可以抛出什么样的异常。但是它不只是一个有趣的注释。编译器在编译时有时能检测到异常规格的不一致。而且若一个函数抛出一个不在异常规格范围里的异常,系统在运行时能够检测出这个错误,然后一个特殊函数unexpected将被自动地调用。异常规格既可以做为一个指导性文档同时也是异常使用的强制约束机制。)

  看看抛出异常的开销。事实上不用太关心这个问题,因为异常是很少见的,这种事件的发生往往被描述为exceptional(异常的,罕见的)。80-20规则说这样的事件不会对整个程序的性能造成太大的影响。若想知道如果抛出一个异常到底会有多大的开销,答案是这可能会比较大。与一个正常的函数返回相比,通过抛出异常从函数里返回可能会慢三个数量级。这个开销很大。但是仅仅当抛出异常时才会有这个开销,一般不会发生。但是如果用异常表示一个比较普遍的状况,例如完成对数据结构的遍历或结束一个循环,那必须重新予以考虑。

  若支持异常对于大多数编译器是一个较新的特性,若不同的编译器异常方法也不同,那么如何能说程序的尺寸将增大5%-10%,它的速度也同比例减慢,而且如果有大量的异常被抛出,程序运行速度会呈数量级的减慢呢?答案是令人惊恐的:一些传闻和一些基准测试(benchmarks)。事实是大部分人包括编译器生产商在异常处理方面几乎没有什么经验,所以尽管知道异常确实会带来开销,却很难预测出开销的准确数量。

  谨慎的方法是对所叙述的开销有了解,但是不深究具体的数量。(即定性不定量)不论异常处理的开销有多大我们都得坚持只有必须付出时才付出的原则。为了使异常开销最小化,只要可能尽量就采用不支持异常的方法编译程序,把使用try块和异常规格限制在确实需要它们的地方,并且只有在确为异常的情况下(exceptional)才抛出异常。

 
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值