很多帖子都分析过Try-Catch的机制,以及其对性能的影响。

但是并没有证据证明,Try-Catch过于损耗了系统的性能,尤其是在托管环境下。记得园子里有位网友使用StopWatch分析过Try-Catch在不同情况下,与无Try-Catch的代码相比,代码运行的时间指标,结果并没有很大差异。

下面我来结合IL分析一下Try-Catch吧。

● 机制分析

.Net 中基本的异常捕获与处理机制是由try…catch…finally块来完成的,它们分别完成了异常的监测、捕获与处理工作。一个try块可以对应零个或多个catch块,可以对应零个或一个finally块。不过没有catch的try似乎没有什么意义,如果try对应了多个catch,那么监测到异常后,CLR会自上而下搜索catch块的代码,并通过异常过滤器筛选对应的异常,如果没有找到,那么CLR将沿着调用堆栈,向更高层搜索匹配的异常,如果已到堆栈顶部依然没有找到对应的异常,就会抛出未处理的异常了,这时catch块中的代码并不会被执行。所以距离try最近的catch块将最先被遍历到。

如有以下代码:

try 
   {
       Convert.ToInt32("Try");
   }
       catch (FormatException ex1)
   {

string CatchFormatException = "CatchFormatException";
   }
       catch (NullReferenceException ex2)
   {

string CatchNullReferenceException = "CatchNullReferenceException";
   }

finally
   {
       string Finally = "Finally";
   }

对应IL如下:

.method private hidebysig instance void Form1_Load(object sender,

class [mscorlib]System.EventArgs e) cil managed

{

// Code size 53 (0x35)

.maxstack 1

.locals init ([0] class [mscorlib]System.FormatException ex1,

[1] string CatchFormatException,

[2] class [mscorlib]System.NullReferenceException ex2,

[3] string CatchNullReferenceException,

[4] string Finally)

IL_0000: nop

IL_0001: nop

IL_0002: ldstr "Try"

IL_0007: call int32 [mscorlib]System.Convert::ToInt32(string)

IL_000c: pop

IL_000d: nop

IL_000e: leave.s IL_0026

IL_0010: stloc.0

IL_0011: nop

IL_0012: ldstr "CatchFormatException"

IL_0017: stloc.1

IL_0018: nop

IL_0019: leave.s IL_0026

IL_001b: stloc.2

IL_001c: nop

IL_001d: ldstr "CatchNullReferenceException"

IL_0022: stloc.3

IL_0023: nop

IL_0024: leave.s IL_0026

IL_0026: nop

IL_0027: leave.s IL_0033

IL_0029: nop

IL_002a: ldstr "Finally"

IL_002f: stloc.s Finally

IL_0031: nop

IL_0032: endfinally

IL_0033: nop

IL_0034: ret

IL_0035:

// Exception count 3

.try IL_0001 to IL_0010 catch [mscorlib]System.FormatException handler IL_0010 to IL_001b

.try IL_0001 to IL_0010 catch [mscorlib]System.NullReferenceException handler IL_001b to IL_0026

.try IL_0001 to IL_0029 finally handler IL_0029 to IL_0033

} // end of method Form1::Form1_Load

末尾的几行代码揭示出IL是怎样处理异常处理的。最后三行的每一个Item被称作Exception Handing Clause,EHC组成Exception Handing Table,EHT与正常代码之间由ret返回指令隔开。

可以看出,FormatException排列在EHT的第一位。

当代码成功执行或反之而返回后,CLR会遍历EHT:

1. 如果抛出异常, CLR会根据抛出异常的代码的“地址”找到对应的EHC(IL_0001 to IL_0010为检测代码的范围),这个例子中CLR将找到2条EHC,FormatException会最先被遍历到,且为适合的EHC。

2. 如果返回的代码地址在IL_0001 to IL_0029内,那么还会执行finally handler IL_0029 to IL_0033中的代码,不管是否因成功执行代码而返回

事实上,catch与finally的遍历工作是分开进行的,如上文所言,CLR首先做的是遍历catch,当找到合适的catch块后,再遍历与之对应finally;而且这个过程会递归进行至少两次,因为编译器将C#的try…catch…finally翻译成IL中的两层嵌套。

当然如果没有找到对应的catch块,那么CLR会直接执行finally,然后立即中断所有线程。Finally块中的代码肯定会被执行,无论try是否检测到了异常。

● 改进建议

    由上面的内容可以得出:

    如果使用了“Try-Catch”,且捕获到了异常,CLR做的只不过是遍历Exception Handing Table中的Catch项;然后再次遍历Exception Handing Table中的Finally项,所用时间几乎都花费在遍历Exception Handing Table上;而如果没有捕获到异常,CLR只是遍历Exception Handing Table中的Finally项,所需时间微乎其微。

而“Try-Catch”遍历后的执行对应操作所用时间,则根据你的具体代码所定,“Try-Catch”引起的只是监控与触发,不应将这部分的代码时间也算“Try-Catch”的消耗。

所以,可以从性能和代码评审两方面考虑,一般建议有以下几点准则:

1.尽量给CLR一个明确的异常信息,不要使用Exception去过滤异常

2.尽量不要将try…catch写在循环中

3. try尽量少的代码,如果有必要可以使用多个catch块,并且将最有可能抛出的异常类型,书写在距离try最近的位置

4.不要只声明一个Exception对象,而不去处理它。这样做白白增加了Exception Handing Table的长度。

5.使用性能计数器实用工具的“CLR Exceptions”检测异常情况,并适当优化

6.使用成员的Try-Parse模式,如果抛出异常,那么用false代替它

结论,Try-Catch虽然会消费一点时间,但程序人员大可不必谈虎色变,通过上面的分析,与其说“Try-Catch”会损耗或影响性能,不如说“Try-Catch”与其他代码一样,只是性能的普通消费者,但出于代码书写评审方面的考虑,还是尽量关照一下“Try-Catch”吧。

Try-Catch真的会影响程序性能吗的更多相关文章

  1. java的编程习惯影响程序性能

    在Java程序中,性能问题的大部分原因并不在于Java语言,而是在于程序本身. 养成良好的编程习惯非常重要,能够显著地提升程序性能. 尽量在合适的场合使用单例 使用单例可以减轻加载的负担,缩短加载的时 ...

  2. iOS 程序性能优化

    前言 转载自:http://www.samirchen.com/ios-performance-optimization/ 程序性能优化不应该是一件放在功能完成之后的事,对性能的概念应该从我们一开始写 ...

  3. 流言粉碎机:JAVA使用 try catch 会严重影响性能

    目录 一.JVM 异常处理逻辑 二.关于JVM的编译优化 1. 分层编译 2. 即时编译器 1. 解释模式 2. 编译模式 3. 提前编译器:jaotc 三.关于测试的约束 执行用时统计 编译器优化的 ...

  4. C# 程序性能提升篇-2、类型(字段类型、class和struct)的错误定义所影响性能浅析

    前景提要: 编写程序时,也许你不经意间,就不知不觉的定义了错误的类型,从而发生了额外的性能消耗,从而降低了效率,不要说就发生那么一次两次,如果说是程序中发生了循环.网络程序(不断请求处理的)等这些时候 ...

  5. 从系统的角度分析影响程序执行性能的因素——SA20225205 黄兴宇

    实验总结分析报告:从系统的角度分析影响程序执行性能的因素 1.请您根据本课程所学内容总结梳理出一个精简的Linux系统概念模型,最大程度统摄整顿本课程及相关的知识信息,模型应该是逻辑上可以运转的.自洽 ...

  6. [.net 面向对象程序设计进阶] (15) 缓存(Cache)(二) 利用缓存提升程序性能

    [.net 面向对象程序设计进阶] (15) 缓存(Cache)(二) 利用缓存提升程序性能 本节导读: 上节说了缓存是以空间来换取时间的技术,介绍了客户端缓存和两种常用服务器缓布,本节主要介绍一种. ...

  7. java程序性能优化

    一.避免在循环条件中使用复杂表达式 在不做编译优化的情况下,在循环中,循环条件会被反复计算,如果不使用复杂表达式,而使循环条件值不变的话,程序将会运行的更快. 例子: import java.util ...

  8. C# 关于Try/Catch对系统性能影响的总结

    自从开始考虑代码的运行效率和性能以后,写代码考虑的东西越来越多了,比如什么时候应该加try/catch?加太多的try/catch会不会降低性能?今天就来分享一下对try/catch对性能影响的一些看 ...

  9. 25个增强iOS应用程序性能的提示和技巧(初级篇)

    25个增强iOS应用程序性能的提示和技巧(初级篇) 标签: ios内存管理性能优化 2013-12-13 10:53 916人阅读 评论(0) 收藏 举报  分类: IPhone开发高级系列(34)  ...

随机推荐

  1. javascript中childNodes与children的区别

    1.childNodes:获取节点,不同浏览器表现不同: IE:只获取元素节点: 非IE:获取元素节点与文本节点: 解决方案:if(childNode.nodeName=="#text&qu ...

  2. shell脚本杀进程重启

    #!/bin/bash ID=`ps -ef | grep "abc" | grep -v "$0" | grep -v "grep" | ...

  3. js继承的实现(es5)

    js对面向对象的支持很弱,所以在ES6之前实现继承会绕比较多的弯(类似于对面向对象支持弱,然后强行拼凑面向对象的特性) es5中实现继承的几种方式,父类定义为Super function Super( ...

  4. hadoop nameNode 无法启动

    /************************************************************STARTUP_MSG: Starting NameNodeSTARTUP_M ...

  5. jQuery插件开发之boxScroll与marquee

    BoxScroll 常见图片轮播效果的简单实现.可以数字列表控制或者左右按键控制.逻辑很简单,下面的Marquee形成环,这个到了尽头得往回跑,看看注释就知道了. 图片轮播GitHub:https:/ ...

  6. FPGA加速:面向数据中心和云服务的探索和实践

    欢迎大家前往腾讯云+社区,获取更多腾讯海量技术实践干货哦~ 本文由columneditor 发表于云+社区专栏 作者介绍:章恒--腾讯云FPGA专家,目前在腾讯架构平台部负责FPGA云的研发工作,探索 ...

  7. Delphi 通得进程ID获取主窗口句柄

    只知道进程ID,获取主窗口句柄的方法如下: 通过EnumWindows枚举所有窗口 使用GetWindowThreadProcessID,通过窗口句柄获取进程ID 比便获取的进程ID与当前已知的进程I ...

  8. [转]使用ASP.NET Web Api构建基于REST风格的服务实战系列教程【八】——Web Api的安全性

    本文转自:http://www.cnblogs.com/fzrain/p/3552423.html 系列导航地址http://www.cnblogs.com/fzrain/p/3490137.html ...

  9. checkebox 全选 ,子复选框单个全部选择后,全选框也会被选择

    <script> //点击全选,子复选框被选中 function demo(){ var allcheck=document.getElementById("allcheck&q ...

  10. WPF 用户控件嵌入网页

    WPF使用用户控件嵌入网页,直接使用WebBrowser或Frame会产生报错,报错信息如下: 1.使用WebBrowser,<WebBrowser Source="http://19 ...