V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
OneAPM
V2EX  ›  Java

JAVA 异常对于性能的影响

  •  
  •   OneAPM ·
    oneapm · 2015-05-22 14:01:21 +08:00 · 3305 次点击
    这是一个创建于 3479 天前的主题,其中的信息可能已经有所发展或是发生改变。

    Alt text

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

    实验

    我的实验基于一段随机抛出异常的简单代码。从科学的角度,这并非完全准确的测量,同时我也并不了解 HotSpot 编译器会对运行中的代码做何动作。但无论如何,这段代码应该能够让我们了解一些基本情况。
    结果很有意思:抛出与捕获异常的代价似乎极低。在我的例子里,大约是每个异常 0.02 毫秒。除非你真的抛出太多异常(我们指的是 10 万次或者更多),否则这一点基本都可忽略。 尽管这些结果显示出异常处理本身并不影响代码性能,但却并未解决下面这个问题:异常对性能的巨大影响该由谁负责?
    Alt text

    我明显遗漏了什么重要的问题。

    重新想了一下,我意识到自己遗漏了异常处理的一个重要部分。我没考虑到异常发生时你做了什么。在多数情况下你很有可能不仅仅是捕获异常!而问题就在这里:一般情况下,你会试图对问题进行补充,并让应用在最终用户那里仍能发挥功能。所以我遗漏的就是:“”为了处理异常而执行的补充代码“”。按照补充代码的不同,性能损失可能会变得相当显著。在某些情况下这可能意味着重试连接到服务器,在另一些情况下则可能意味着使用默认的回滚方案,而这种方案提供的解决办法肯定会带来非常差劲的性能。对于我们在很多情况下看到的行为,这似乎给出了很好的解释。

    不过我却不觉得分析到这里已经万事大吉,而是感到这里还遗漏了别的什么东西。

    Stack trace

    对此问题,我仍颇为好奇,为此监视了收集 strack trace 时情况性能有何变化。

    经常发生的情况应该是这样的:记下异常及其栈轨迹,尝试找出问题到底在哪。

    为此我修改了代码,额外收集了异常的 strack trace 。这让情况显著改变。对异常的 strack trace 的收集,其性能影响要比单纯捕获并抛出异常高出10倍。因此尽管 strack trace 有助于理解哪里发生了问题(有可能还有助于理解为何发生问题),但却存在性能损失。 由于我们谈论的并非一条 strack trace,所以此处的影响往往非常之大。 多数情况下,我们都要在多个层次上抛出并捕获异常。 我们看一个简单的例子: Web 服务客户端连接到服务器。首先,Java 库级别上存在一个连接失败异常。此后会有框架级别上的客户端失败异常,再以后可能还会有应用层次上的业务逻辑调用失败异常。到现在为止,总共要搜集三条strack trace。 多数情况下,你都能从日志文件或者应用输出中看到这些 strack trace,而写入这些较长的 strack trace 往往也会也带来性能影响。

    结论

    首先因为存在性能影响而把异常弃之不用并非良策。异常有助于提供一种一致的方式来解决运行时问题,并且有助于写出干净的代码。但我们应该对代码中抛出的异常数量进行跟踪,它们可能导致显著的性能影响。所以 OneAPM 默认要对所抛出的异常进行跟踪——在很多情况下人们都会对代码中发生的异常以及在解决这些异常时的性能损耗感到吃惊不已。 其次尽管使用异常很有裨益,您也应避免捕获过多的 strack trace。异常应该是为异常的情况而设计的,使用时应该牢记这一原则。当然,万一您不想遵从好的编程习惯,Java 语言就会让您知道,那样做可以让您的程序运行得更快,从而鼓励您去那样做。

    本文作者系OneAPM工程师编译整理,想阅读更多技术文章,请访问OneAPM官方技术博客

    Alt text

    13 条回复    2015-05-22 21:25:49 +08:00
    liprais
        1
    liprais  
       2015-05-22 14:19:00 +08:00
    1.这里不欢迎原文转帖,贴链接即可
    2.编译整理不给出原文链接,节操呢?
    OneAPM
        2
    OneAPM  
    OP
       2015-05-22 14:36:01 +08:00
    @liprais 抱歉,全文是为了来方便阅读,那以后只放半篇吧。欢迎对内容做出更多评价 :)
    liprais
        3
    liprais  
       2015-05-22 14:40:36 +08:00
    @OneAPM 如果是转载的话,贴链接即可.
    另外本篇的原文链接呢?如果是翻译的话务必附上全文链接
    shiznet
        4
    shiznet  
       2015-05-22 14:50:18 +08:00
    除了标题,所有的stack都写错了
    hjxx
        5
    hjxx  
       2015-05-22 15:01:49 +08:00
    感觉是翻译文?读起来怪怪的 跟livid的行文风格一样。。
    Septembers
        6
    Septembers  
       2015-05-22 15:01:58 +08:00   ❤️ 2
    1. 代码没格式化 节操 这是不让阅读的意思?
    2. 大小写错误(JAVA -> Java
    3. 拼写错误(strack trace -> stacktrace
    4. 原则上禁止全文转载(参考ToS和FAQ

    5. 讨论没深度
    5.1. 没深入探讨JLSpec, JVMSpec的定义细节
    5.2. 没深入探讨OpenJDK的实现细节

    6. @OneAPM 难道只是为了在这里刷存在感?
    sumhat
        7
    sumhat  
       2015-05-22 15:12:52 +08:00
    这代码格式也是醉了,如果你们产品也都写成这样,应该不会有人用的吧
    OneAPM
        8
    OneAPM  
    OP
       2015-05-22 16:17:04 +08:00
    @shiznet sorry,多谢提醒!
    @Septembers
    @sumhat 时间久了,工程师已经把代码删了。
    sampeng
        9
    sampeng  
       2015-05-22 16:28:05 +08:00
    看这帖子真木意思。。刷存在感么?
    OneAPM
        10
    OneAPM  
    OP
       2015-05-22 16:30:12 +08:00   ❤️ 1
    @sampeng 抱歉,以后我们不发这位作者的文章了 :)
    hitsmaxft
        11
    hitsmaxft  
       2015-05-22 18:11:31 +08:00
    没必要地抛出异常肯定是浪费资源, try 又不是拿来规避错误的。

    只是你这文章基本啥都没说。。。。。
    wwqgtxx
        12
    wwqgtxx  
       2015-05-22 19:41:05 +08:00 via Android
    @liprais
    @Septembers
    请看最新的Tos https://www.v2ex.com/about
    1. V2EX 不反对文章的原作者自己全文转载自己写的原创文章

    Last Revised 2015-05-15 01:37:09 +08:00
    cloud107202
        13
    cloud107202  
       2015-05-22 21:25:49 +08:00
    我觉得这种分享氛围很好,大家没必要太苛刻了
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   2936 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 24ms · UTC 03:27 · PVG 11:27 · LAX 19:27 · JFK 22:27
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.