Try-Catch真的会影响程序性能吗
今天和TL争论try-catch使用上的问题,是否为了代码看上去的美观而把该方法下得所有代码都放到try-catch中,我理所当然的持反对意见,但对try-catch的实现机制没有深入研究过,不能说出有说服力的理由,今天在网上找到个.net的try-catch分析,和大家分享下
很多帖子都分析过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”吧。

C#.NET生态系统提供了丰富的框架和库,帮助开发者高效构建应用。1.ASP.NETCore用于构建高性能Web应用,2.EntityFrameworkCore用于数据库操作。通过理解这些工具的使用和最佳实践,开发者可以提高应用的质量和性能。

如何将C#.NET应用部署到Azure或AWS?答案是使用AzureAppService和AWSElasticBeanstalk。1.在Azure上,使用AzureAppService和AzurePipelines自动化部署。2.在AWS上,使用AmazonElasticBeanstalk和AWSLambda实现部署和无服务器计算。

C#和.NET的结合为开发者提供了强大的编程环境。1)C#支持多态性和异步编程,2).NET提供跨平台能力和并发处理机制,这使得它们在桌面、Web和移动应用开发中广泛应用。

.NETFramework是一个软件框架,C#是一种编程语言。1..NETFramework提供库和服务,支持桌面、Web和移动应用开发。2.C#设计用于.NETFramework,支持现代编程功能。3..NETFramework通过CLR管理代码执行,C#代码编译成IL后由CLR运行。4.使用.NETFramework可快速开发应用,C#提供如LINQ的高级功能。5.常见错误包括类型转换和异步编程死锁,调试需用VisualStudio工具。

C#是一种由微软开发的现代、面向对象的编程语言,.NET是微软提供的开发框架。C#结合了C 的性能和Java的简洁性,适用于构建各种应用程序。.NET框架支持多种语言,提供垃圾回收机制,简化内存管理。

C#和.NET运行时紧密合作,赋予开发者高效、强大且跨平台的开发能力。1)C#是一种类型安全且面向对象的编程语言,旨在与.NET框架无缝集成。2).NET运行时管理C#代码的执行,提供垃圾回收、类型安全等服务,确保高效和跨平台运行。

要开始C#.NET开发,你需要:1.了解C#的基础知识和.NET框架的核心概念;2.掌握变量、数据类型、控制结构、函数和类的基本概念;3.学习C#的高级特性,如LINQ和异步编程;4.熟悉常见错误的调试技巧和性能优化方法。通过这些步骤,你可以逐步深入C#.NET的世界,并编写高效的应用程序。

C#和.NET的关系是密不可分的,但它们不是一回事。C#是一门编程语言,而.NET是一个开发平台。C#用于编写代码,编译成.NET的中间语言(IL),由.NET运行时(CLR)执行。


热AI工具

Undresser.AI Undress
人工智能驱动的应用程序,用于创建逼真的裸体照片

AI Clothes Remover
用于从照片中去除衣服的在线人工智能工具。

Undress AI Tool
免费脱衣服图片

Clothoff.io
AI脱衣机

Video Face Swap
使用我们完全免费的人工智能换脸工具轻松在任何视频中换脸!

热门文章

热工具

螳螂BT
Mantis是一个易于部署的基于Web的缺陷跟踪工具,用于帮助产品缺陷跟踪。它需要PHP、MySQL和一个Web服务器。请查看我们的演示和托管服务。

EditPlus 中文破解版
体积小,语法高亮,不支持代码提示功能

ZendStudio 13.5.1 Mac
功能强大的PHP集成开发环境

安全考试浏览器
Safe Exam Browser是一个安全的浏览器环境,用于安全地进行在线考试。该软件将任何计算机变成一个安全的工作站。它控制对任何实用工具的访问,并防止学生使用未经授权的资源。

SublimeText3 Mac版
神级代码编辑软件(SublimeText3)