摘要:对异常的的收集,其性能影响要比单纯捕获并抛出异常高出倍。但我们应该对代码中抛出的异常数量进行跟踪,它们可能导致显著的性能影响。
在对我们的客户做技术支持时,我们常常会看到很多客户根本没意识到的异常。在消除了这些异常之后,代码运行速度与以前相比大幅提升。这让我们产生一种猜测,就是在代码里面使用异常会带来显著的性能开销。因为异常是错误情况处理的重要组成部分,摒弃是不太可能的,所以我们需要衡量异常处理对于性能影响,我们可以通过一个实验看看异常处理的对于性能的影响。
实验我的实验基于一段随机抛出异常的简单代码。从科学的角度,这并非完全准确的测量,同时我也并不了解HotSpot 编译器会对运行中的代码做何动作。但无论如何,这段代码应该能够让我们了解一些基本情况。
结果很有意思:抛出与捕获异常的代价似乎极低。在我的例子里,大约是每个异常 0.02 毫秒。除非你真的抛出太多异常(我们指的是 10 万次或者更多),否则这一点基本都可忽略。 尽管这些结果显示出异常处理本身并不影响代码性能,但却并未解决下面这个问题:异常对性能的巨大影响该由谁负责?
我明显遗漏了什么重要的问题。重新想了一下,我意识到自己遗漏了异常处理的一个重要部分。我没考虑到异常发生时你做了什么。在多数情况下你很有可能不仅仅是捕获异常!而问题就在这里:一般情况下,你会试图对问题进行补充,并让应用在最终用户那里仍能发挥功能。所以我遗漏的就是:“”为了处理异常而执行的补充代码“”。按照补充代码的不同,性能损失可能会变得相当显著。在某些情况下这可能意味着重试连接到服务器,在另一些情况下则可能意味着使用默认的回滚方案,而这种方案提供的解决办法肯定会带来非常差劲的性能。对于我们在很多情况下看到的行为,这似乎给出了很好的解释。
不过我却不觉得分析到这里已经万事大吉,而是感到这里还遗漏了别的什么东西。
Stack trace对此问题,我仍颇为好奇,为此监视了收集 strack trace 时情况性能有何变化。
经常发生的情况应该是这样的:记下异常及其栈轨迹,尝试找出问题到底在哪。
为此我修改了代码,额外收集了异常的 strack trace 。这让情况显著改变。对异常的 strack trace 的收集,其性能影响要比单纯捕获并抛出异常高出10倍。因此尽管 strack trace 有助于理解哪里发生了问题(有可能还有助于理解为何发生问题),但却存在性能损失。 由于我们谈论的并非一条 strack trace,所以此处的影响往往非常之大。 多数情况下,我们都要在多个层次上抛出并捕获异常。 我们看一个简单的例子: Web 服务客户端连接到服务器。首先,Java 库级别上存在一个连接失败异常。此后会有框架级别上的客户端失败异常,再以后可能还会有应用层次上的业务逻辑调用失败异常。到现在为止,总共要搜集三条strack trace。 多数情况下,你都能从日志文件或者应用输出中看到这些 strack trace,而写入这些较长的strack trace 往往也会也带来性能影响。
结论首先因为存在性能影响而把异常弃之不用并非良策。异常有助于提供一种一致的方式来解决运行时问题,并且有助于写出干净的代码。但我们应该对代码中抛出的异常数量进行跟踪,它们可能导致显著的性能影响。所以我们默认要对所抛出的异常进行跟踪——在很多情况下人们都会对代码中发生的异常以及在解决这些异常时的性能损耗感到吃惊不已。 其次尽管使用异常很有裨益,您也应避免捕获过多的 strack trace。异常应该是为异常的情况而设计的,使用时应该牢记这一原则。当然,万一您不想遵从好的编程习惯,Java 语言就会让您知道,那样做可以让您的程序运行得更快,从而鼓励您去那样做。
本文作者系 OneAPM 工程师陶炳哲。想阅读更多技术文章,请访问OneAPM 官方技术博客。
文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。
转载请注明本文地址:https://www.ucloud.cn/yun/65299.html
摘要:允许存在多个,用于针对不同的异常做不同的处理。表示程序可能需要捕获并且处理的异常。因此,我们应该尽可能的避免通过异常来处理正常的逻辑检查,这样可以确保不会因为发生异常而导致性能问题。异常表中的每一条记录,都代表了一个异常处理器。 showImg(https://segmentfault.com/img/remote/1460000017918154?w=640&h=100); show...
摘要:分析性能的影响但是需要注意时间单位,只是微秒而已,毫秒的千分之一秒的百万分之一。在这种情况下,优化毫秒的性能隐患无异于捡了芝麻丢了西瓜。 同步自:https://sulin.me/2019/T2ZXZB.... 在分布式系统开发中,我们经常需要将各种各样的状态码、错误信息传递给最外层的调用方,这个调用方通常是http/api接口,错误信息比如登录失效、参数错误等等。 最外层接口暴露的...
摘要:声明本文所有列举的问题都来源于编程随想的博客,这个博客的博主知识渊博,编程方面的一些文章质量很高,给人醍醐灌顶的感觉。 声明:本文所有列举的问题都来源于 《编程随想》的博客,这个博客的博主知识渊博,编程方面的一些文章质量很高,给人醍醐灌顶的感觉。 算法和数据结构 什么时候该用数组类型容器,什么时候该用链表型容器,如何合理的使用数据类型 什么是散列函数,HashMap的实现原理是什么 ...
摘要:代码优化的最重要的作用应该是避免未知的错误。此举能够使性能平均提高。抛出异常首先要创建一个新的对象,接口的构造函数调用名为的本地同步方法,方法检查堆栈,收集调用跟踪信息。异常只能用于错误处理,不应该用来控制程序流程。 showImg(https://segmentfault.com/img/remote/1460000015379073); 代码优化的最重要的作用应该是:避免未知的错误...
摘要:此举能够使性能平均提高。尽可能使用局部变量调用方法时传递的参数以及在调用中创建的临时变量都保存在栈中速度较快,其他变量,如静态变量实例变量等,都在堆中创建,速度较慢。 showImg(https://segmentfault.com/img/bVbsIIl?w=900&h=383);本文来源 | http://atjf.top/3WLPmG 作者 | 萌小Q 01前沿 代码优化 ,一个...
阅读 4077·2021-10-08 10:04
阅读 3060·2021-08-11 11:20
阅读 2730·2021-07-25 21:37
阅读 2680·2019-08-30 12:44
阅读 2305·2019-08-30 11:12
阅读 1313·2019-08-26 13:45
阅读 2337·2019-08-26 11:53
阅读 3056·2019-08-26 11:32