Java的异常处理对于性能的影响
  • 快科技
  • 2015年04月22日 11:29
  • 0

在对OneAPM的客户做技术支持时,我们常常会看到很多客户根本没意识到的异常。在消除了这些异常之后,代码运行速度与以前相比大幅提升。这就让我们产生一种猜测,也就是在代码里面使用异常会带来显著的性能开销。不过由于异常是错误情况处理的重要组成部分,完全摒弃也是不太可能的。那么异常处理对于性能影响到底有多大呢?我们来做个实验看看。

实验

我的实验基于一段随机抛出异常的简单代码。从科学的角度,这并非真正深入的测量;而且我们也并不了解HotSpot编译器会对运行中的代码做何动作。但无论如何,这段代码应该能够让我们了解一些基本情况:

结果

结果很有意思。抛出与捕获异常的代价似乎极低。在我的例子里,大约是每个异常0.02毫秒。除非你真的抛出太多异常(我们说的是10万次或者更多),否则这一点基本都可忽略。

尽管这些结果显示出异常处理本身并不影响代码性能,但却并未解决下面这个问题:异常对性能的巨大影响该由谁负责?因此我明显遗漏了什么重要的地板供需。

重新想了一下,我意识到自己遗漏了异常处理的一个重要部分。我没考虑到异常发生时你做了什么。在多数情况下你很有可能不仅仅是捕获异常,而问题就在这里。

一般情况下,你会试图对问题进行补充,并让应用在最终用户那里仍能发挥功能。所以我遗漏的就是为了处理异常而执行的补充代码。按照补充代码的不同,性能损失可能变得相当显著。在某些情况下这可能意味着重试连接到服务器,在其他情况下则可能意味着使用默认的后退解决方案,而这种方案提供的解决办法却会带来差得多的性能。

对于我们在很多情况下看到的行为,这似乎给出了很好的解释。不过我却不觉得分析已经万事大吉,而是感到这里还遗漏了别的什么东西。

栈轨迹

对此问题,我仍颇为好奇,为此审视了收集栈轨迹时情况有何变化。经常发生的也不过如此:

记下异常及其栈轨迹,以尝试找出问题为何。

为此我修改了代码,额外收集了异常的栈轨迹。这让情况显著改变。对异常的栈轨迹的收集,其性能影响要比单纯捕获并抛出异常高出10倍。因此尽管栈轨迹有助于理解哪里发生了问题(有可能还有助于理解为何发生问题),但却存在性能损失。

由于我们谈论的并非一条栈轨迹,所以此处的影响往往非常之大。多数情况下,我们都要在多个层次上抛出并捕获异常。我们看一个简单的例子:

Web服务客户端连接到服务器。首先,Java库级别上存在一个连接失败异常。此后会有框架级别上的客户端失败异常,再以后可能还会有应用层次上的业务逻辑调用失败异常。到现在为止,总共要搜集三条栈轨迹。

多数情况下,你都能从日志文件或者应用输出中看到这些栈轨迹。写入这些较长的栈轨迹也带来了性能影响。如果你定期查看日志文件的话,至少你应该都能看到它们并做出反应——你真的定期查看日志文件,对吧?

结论

因为存在性能影响而把异常弃之不用并非良策。异常有助于提供一种一致的方式来解决运行时问题,并且有助于写出干净的代码。但却需要对代码中抛出的异常数量进行跟踪,它们可能存在显著的性能影响。在OneAPM中我们默认要对所抛出的异常进行跟踪——而在很多情况下人们都会对代码中发生的异常以及在解决这些异常时的性能影响感到吃惊不已。

不过尽管使用异常很有裨益,您也应避免捕获过多的栈轨迹。异常应该是为异常的情况而设计的,使用时也应该牢记这一原则。但是,万一您不想遵从好的编程习惯,Java语言就会让您知道,那样做可以让您的程序运行得更快,从而鼓励您去那样做。


文章出处:IT168

文章纠错

  • 好文点赞
  • 水文反对

此文章为快科技原创文章,快科技网站保留文章图片及文字内容版权,如需转载此文章请注明出处:快科技

观点发布 网站评论、账号管理说明
热门评论
查看全部评论
相关报道

最热文章排行查看排行详情

邮件订阅

评论0 | 点赞0| 分享0 | 收藏0