范文健康探索娱乐情感热点
投稿投诉
热点动态
科技财经
情感日志
励志美文
娱乐时尚
游戏搞笑
探索旅游
历史星座
健康养生
美丽育儿
范文作文
教案论文
国学影视

扯什么trycatch性能问题?

  你看着这鬼代码,竟然在 for 循环里面搞了个 try-catch,不知道try-catch有性能损耗吗?"老陈煞有其事地指着屏幕里的代码: for (int i = 0; i < 5000; i++) {      try {          dosth      } catch (Exception e) {          e.printStackTrace();      }  } 复制代码
  我探过头去看了眼代码,"那老陈你觉得该怎么改?"
  "当然是把 try-catch 提到外面啊!"老陈脑子都不转一下,脱口而出。
  "你是不是傻?且不说性能,这代码的目的明显是让循环内部单次调用出错不影响循环的运行,你其到外面业务逻辑不就变了吗!"
  老陈挠了挠他的地中海,"好像也是啊!"
  "回过头来,catch 整个 for 循环和在循环内部 catch,在不出错的情况下,其实性能差不多。" 我喝一口咖啡不经意地提到,准备在老陈前面秀一下。
  "啥意思?"老陈有点懵地看着我,"try-catch是有性能损耗的,我可是看过网上资料的!"
  果然,老陈上钩了,我二话不说直接打开 idea,一顿操作敲了以下代码:public class TryCatchTest {      @Benchmark     public void tryfor(Blackhole blackhole) {         try {             for (int i = 0; i < 5000; i++) {                 blackhole.consume(i);             }         } catch (Exception e) {             e.printStackTrace();         }     }      @Benchmark     public void fortry(Blackhole blackhole) {         for (int i = 0; i < 5000; i++) {             try {                 blackhole.consume(i);             } catch (Exception e) {                 e.printStackTrace();             }         }     }  } 复制代码
  "BB 不如 show code,看到没,老陈,我把 try-catch 从 for 循环里面提出来跟在for循环里面做个对比跑一下,你猜猜两个差多少?"
  "切,肯定 tryfor 性能好,想都不用想,不是的话我倒立洗头!"老陈信誓旦旦道。
  我懒得跟他BB,直接开始了 benchmark,跑的结果如下:
  可以看到,两者的性能(数字越大越好)其实差不多:fortry: 86,261(100359-14098) ~ 114,457(100359+14098)tryfor: 95,961(103216-7255) ~ 110,471(103216+7255)
  我再调小(一般业务场景 for 循环次数都不会很多)下 for 循环的次数为 1000 ,结果也是差不多:
  老陈一看傻了:"说好的性能影响呢?怎么没了?"
  我直接一个javap,让老陈看看,其实两个实现在字节码层面没啥区别:
  tryfor 的字节码
  异常表记录的是 0 - 20 行,如果这些行里面的代码出现问题,直接跳到 23 行处理。
  fortry 的字节码
  差别也就是异常表的范围小点,包的是 9-14 行,其它跟 tryfor 都差不多。
  所以从字节码层面来看,没抛错两者的执行效率其实没啥差别。
  "那为什么网上流传着try-catch会有性能问题的说法啊?"老陈觉得非常奇怪。
  这个说法确实有,在《Effective Java》这本书里就提到了 try-catch 性能问题:
  并且还有下面一段话:
  正所谓听话不能听一半,以前读书时候最怕的就是一知半解,因为完全理解选择题能选对,完全不懂蒙可能蒙对,一知半解必定选到错误的选项!
  《Effective Java》书中说的其实是不要用 try-catch 来代替正常的代码,书中的举例了正常的 for 循环肯定这样实现:
  但有个卧龙偏偏不这样实现,要通过 try-catch 拐着弯来实现循环:
  这操作我只能说有点逆天,这两个实现的对比就有性能损耗了。
  我们直接再跑下有try-catch 的代码和没 try-catch的 for 循环区别,代码如下:
  结果如下:
  +-差不多,直接看前面的分数对比,没有 try-catch 的性能确实好些,这也和书中说的 try-catch 会影响 JVM 一些特定的优化说法吻合,但是具体没有说影响哪些优化,我猜测可能是指令重排之类的。性能评测
  话不多说,我们直接来开始今天的测试,本文我们依旧使用 Oracle 官方提供的 JMH(Java Microbenchmark Harness,JAVA 微基准测试套件)来进行测试。
  首先在 pom.xml 文件中添加 JMH 框架,配置如下:     org.openjdk.jmh    jmh-core    {version} 
  完整测试代码如下:import org.openjdk.jmh.annotations.*; import org.openjdk.jmh.runner.Runner; import org.openjdk.jmh.runner.RunnerException; import org.openjdk.jmh.runner.options.Options; import org.openjdk.jmh.runner.options.OptionsBuilder;  import java.util.concurrent.TimeUnit;  /**  * try - catch 性能测试  */ @BenchmarkMode(Mode.AverageTime) // 测试完成时间 @OutputTimeUnit(TimeUnit.NANOSECONDS) @Warmup(iterations = 1, time = 1, timeUnit = TimeUnit.SECONDS) // 预热 1 轮,每次 1s @Measurement(iterations = 5, time = 5, timeUnit = TimeUnit.SECONDS) // 测试 5 轮,每次 3s @Fork(1) // fork 1 个线程 @State(Scope.Benchmark) @Threads(100) public class TryCatchPerformanceTest {     private static final int forSize = 1000; // 循环次数     public static void main(String[] args) throws RunnerException {         // 启动基准测试         Options opt = new OptionsBuilder()                 .include(TryCatchPerformanceTest.class.getSimpleName()) // 要导入的测试类                 .build();         new Runner(opt).run(); // 执行测试     }      @Benchmark     public int innerForeach() {         int count = 0;         for (int i = 0; i < forSize; i++) {             try {                 if (i == forSize) {                     throw new Exception("new Exception");                 }                 count++;             } catch (Exception e) {                 e.printStackTrace();             }         }         return count;     }      @Benchmark     public int outerForeach() {         int count = 0;         try {             for (int i = 0; i < forSize; i++) {                 if (i == forSize) {                     throw new Exception("new Exception");                 }                 count++;             }         } catch (Exception e) {             e.printStackTrace();         }         return count;     } }
  以上代码的测试结果为:
  从以上结果可以看出,程序在循环 1000 次的情况下,单次平均执行时间为:循环内包含 try-catch 的平均执行时间是 635 纳秒  75 纳秒,也就是 635 纳秒上下误差是 75 纳秒;循环外包含 try-catch 的平均执行时间是 630 纳秒,上下误差 38 纳秒。
  也就是说,在没有发生异常的情况下,除去误差值,我们得到的结论是:try-catch 无论是在 for 循环内还是 for 循环外,它们的性能相同,几乎没有任何差别。
  try-catch的本质
  要理解 try-catch 的性能问题,必须从它的字节码开始分析,只有这样我能才能知道 try-catch 的本质到底是什么,以及它是如何执行的。
  此时我们写一个最简单的 try-catch 代码:public class AppTest {     public static void main(String[] args) {         try {             int count = 0;             throw new Exception("new Exception");         } catch (Exception e) {             e.printStackTrace();         }     } }
  然后使用 javac 生成字节码之后,再使用 javap -c AppTest 的命令来查看字节码文件:  javap -c AppTest  警告: 二进制文件AppTest包含com.example.AppTest Compiled from "AppTest.java" public class com.example.AppTest {   public com.example.AppTest();     Code:        0: aload_0        1: invokespecial #1                  // Method java/lang/Object."":()V        4: return    public static void main(java.lang.String[]);     Code:        0: iconst_0        1: istore_1        2: new           #2                  // class java/lang/Exception        5: dup        6: ldc           #3                  // String new Exception        8: invokespecial #4                  // Method java/lang/Exception."":(Ljava/lang/String;)V       11: athrow       12: astore_1       13: aload_1       14: invokevirtual #5                  // Method java/lang/Exception.printStackTrace:()V       17: return     Exception table:        from    to  target type            0    12    12   Class java/lang/Exception }
  从以上字节码中可以看到有一个异常表:Exception table:        from    to  target type           0    12    12   Class java/lang/Exception
  参数说明:from:表示 try-catch 的开始地址;to:表示 try-catch 的结束地址;target:表示异常的处理起始位;type:表示异常类名称。
  从字节码指令可以看出,当代码运行时出错时,会先判断出错数据是否在 from 到 to 的范围内,如果是则从 target 标志位往下执行,如果没有出错,直接 goto 到 return。也就是说,如果代码不出错的话,性能几乎是不受影响的,和正常的代码的执行逻辑是一样的。
  业务情况分析
  虽然 try-catch 在循环体内还是循环体外的性能是类似的,但是它们所代码的业务含义却完全不同,例如以下代码:public class AppTest {     public static void main(String[] args) {         System.out.println("循环内的执行结果:" + innerForeach());         System.out.println("循环外的执行结果:" + outerForeach());     }          // 方法一     public static int innerForeach() {         int count = 0;         for (int i = 0; i < 6; i++) {             try {                 if (i == 3) {                     throw new Exception("new Exception");                 }                 count++;             } catch (Exception e) {                 e.printStackTrace();             }         }         return count;     }      // 方法二     public static int outerForeach() {         int count = 0;         try {             for (int i = 0; i < 6; i++) {                 if (i == 3) {                     throw new Exception("new Exception");                 }                 count++;             }         } catch (Exception e) {             e.printStackTrace();         }         return count;     } }
  以上程序的执行结果为:
  java.lang.Exception: new Exception
  at com.example.AppTest.innerForeach(AppTest.java:15)
  at com.example.AppTest.main(AppTest.java:5)
  java.lang.Exception: new Exception
  at com.example.AppTest.outerForeach(AppTest.java:31)
  at com.example.AppTest.main(AppTest.java:6)
  循环内的执行结果:5
  循环外的执行结果:3
  可以看出在循环体内的 try-catch 在发生异常之后,可以继续执行循环;而循环外的 try-catch 在发生异常之后会终止循环。
  因此我们在决定 try-catch 究竟是应该放在循环内还是循环外,不取决于性能(因为性能几乎相同),而是应该取决于具体的业务场景。
  例如我们需要处理一批数据,而无论这组数据中有哪一个数据有问题,都不能影响其他组的正常执行,此时我们可以把 try-catch 放置在循环体内;而当我们需要计算一组数据的合计值时,只要有一组数据有误,我们就需要终止执行,并抛出异常,此时我们需要将 try-catch 放置在循环体外来执行。
  总结
  本文我们测试了 try-catch 放在循环体内和循环体外的性能,发现二者在循环很多次的情况下性能几乎是一致的。然后我们通过字节码分析,发现只有当发生异常时,才会对比异常表进行异常处理,而正常情况下则可以忽略 try-catch 的执行。但在循环体内还是循环体外使用 try-catch,对于程序的执行结果来说是完全不同的,因此我们应该从实际的业务出发,来决定到 try-catch 应该存放的位置,而非性能考虑。
  好了,我再总结下有关 try-catch 性能问题说法:try-catch 相比较没 try-catch,确实有一定的性能影响,但是旨在不推荐我们用 try-catch 来代替正常能不用 try-catch 的实现,而不是不让用 try-catch。for循环内用 try-catch 和用 try-catch 包裹整个 for 循环性能差不多,但是其实两者本质上是业务处理方式的不同,跟性能扯不上关系,关键看你的业务流程处理。虽然知道try-catch会有性能影响,但是业务上不需要避讳其使用,业务实现优先(只要不是书中举例的那种逆天代码就行),非特殊情况下性能都是其次,有意识地避免大范围的try-catch,只 catch 需要的部分即可(没把握全 catch 也行,代码安全执行第一)。
  "好了,老陈你懂了没?"
  "行啊yes,BB是一套一套的,走请你喝燕麦拿铁!" 老陈一把拉起我,我直接一个挣脱,"少来,我刚喝过咖啡,你那个倒立洗头,赶紧的!"我立马意识到老陈想岔开话题。
  "洗洗洗,我们先喝个咖啡,晚上回去给你洗!"
  晚上22点,老陈发来一张图片:
  你别说,这头发至少比三毛多。

西藏旅行不去这座城市,你一定会后悔01。hr西藏的西藏,是山南提到西藏,你脑海里最先浮出的记忆是什么?或许是雄伟神圣的布达拉宫,这座以世界屋脊为基石的宫殿,在这天地交汇的地方,升起了关于信仰的图腾。布达拉宫或许是温在广州,这个新晋的车友打卡地,你来过吗?疫情被隔离在家的时候,总是在想能出去走走该多好!等解封了之后,又在想夜市景区商场开业了就好了等到开业之后又在想,生活好无聊没什么新奇的!不知道,大家有没有这样的感受呢?过于单调的生上海宝格丽住一晚要多少钱?金额吓退了不少人,连厕所都住不起近年来,旅游业一直是中国大力支持的行业。去年,由于不可抗力,陷入了低谷期,不仅在旅游业,许多与旅游业密切相关的行业也出现了低谷。然而,如今,旅游业已经经历了全面复苏,所有地区的景点退休大妈爬昆明摩天岭海拔2450多米风景绝美令人神醉刚来昆明没有几天就开始在网上搜索昆明附近有什么山可以爬,因为以前一直居住在重庆,重庆是一座山城,几乎每到周末就要跟驴友一起出去爬山。所以来到昆明住了几天脚就开始闲不住了。经过一番搜无锡太湖游横跨江浙两个省,中国第三淡水湖。传说陨石从天降,造成巨大冲击坑。百里太湖吳越地,天然湖泊风景区。光福景区在湖东,山水古镇湖湾港。梅桂花木香雪海,吳越文化传古今。阳羡景区在西岸,溶洞乡村旅游建设中的传统民居与工艺乡村旅游建设中的传统民居与工艺随着乡村振兴,建设新农村,不少乡村结合当地风俗传统,建起了许多传统民居,利用当地旅游资源,以增加当地收入。而采用传统工艺,可以更好吸引人气,使人们通过无锡融创怎么了?公告说1计划于10月15日开始的异界寻梦季主题活动正式取消,营业时间调整为10001800,期间游乐设备及演出均正常开放(以当天实际开放为准)。210月17日起无锡融创乐园(室外乐印度百年吊桥为何重新开放仅5天就坍塌?印度古吉拉特邦莫尔比市的百年吊桥10月30日坍塌,导致至少141人遇难,另有至少177人已获救,失踪人数不明。印度警方已经逮捕9人,均与负责维护和运营该吊桥的公司有关联。事发当天,国家3A级旅游景区,湛江1!等你来打卡好消息好消息湛江特呈岛被确定为国家3A级旅游景区啦湛江市文化广电旅游体育局关于确定湛江市特呈全域旅游岛景区为国家3A级旅游景区的公告特呈岛宛若湛江港湾一颗晶莹的翡翠它东临太平洋,西济南近郊周末徒步首选之地藏龙涧(龙洞风景区)首游探路笔记路线我走的是浆水泉藏龙涧一线天步行栈道这条路线。1浆水泉上山,全程景色草甸森林,有点小时候剑侠情缘里的画面感,有小路,行进难度较低。整体走了一个小时左右。浆水泉入口处上山处景色1景全国1。11亿个体工商户超八成无需缴税两年多来累计减税降费超万亿视频加载中21世纪经济报道记者王峰北京报道国务院新闻办公室11月1日举行国务院政策例行吹风会,介绍促进个体工商户发展条例有关情况。市场监管总局副局长蒲淳介绍,我国个体工商户焕发出强
羊了个羊火爆全网,玩了几百局后,我领悟了三个人生真相文进击的苯编辑MBA智库琉琉这几天,一款名叫羊了个羊的三消小游戏突然风靡起来。短短几天时间,微博阅读次数近30亿,讨论次数超33万。这款游戏规则很简单,页面上方重叠着各类方块,下方FERRAGAMO更名焕新,年轻化战略初见成效图片来源FERRAGAMO上周,正值米兰时装周拉开帷幕之际,意大利老牌时装屋SalvatoreFerragamo宣布正式更名为FERRAGAMO,品牌全新logo由著名平面设计师P男士相亲戴什么手表好?头条创作挑战赛相亲作为重要场合,展现自我良好的精神风貌和经济实力,还是很有必要的。好好收拾一下再出现,不仅可以提高相亲的成功率,也是对自己对相亲对象对介绍人的尊重。手表作为体现个人双赢交易?曝利物浦巴萨冬窗酝酿轰动转会!巴西荷兰国脚互换东家北京时间9月25日晚,来自西班牙知名媒体每日体育报的透露,欧洲两大豪门巴萨和利物浦计划在冬窗酝酿一笔轰动的互换交易。巴萨计划将荷兰国脚德佩送去利物浦,以换取巴西射手菲尔米诺在同一时中超积分榜三镇优势缩水泰山重燃卫冕希望,沧州保级警报暂解除北京时间9月25日,中超第17轮的补赛战罢,积分榜上也出现了较大的变化。武汉三镇领跑优势缩小到4分,海港的积分追平了排名第4的河南嵩山龙门。沧州雄狮爆冷击败武汉三镇之后,领先降级区伊卡尔迪半生给大哥戴绿帽出轨,遭梅西排挤,净身出户毁前程我们不理解,为何巴黎圣日耳曼宁愿带五个门将也要将昔日意甲神锋伊卡尔迪扫地出门我们不理解,为何阿根廷国家队无论如何都不愿意带上曾经两届意甲最佳射手,即便是替补也不可以,但是天道好轮回象棋夺子取胜技巧声东击西,两翼包抄如图所示,是局选自1995年全国象棋个人赛中,广东庄玉庭与火车头体协金波的实战。双方以仙人指路对卒底炮流行阵式而布局。战至十四回合,枰面七看似平淡无奇,此时,实战红方却暗暗酝酿谋子全靠对手衬托?六年来首胜,赚钱最重要北京时间9月26日,2022年网球拉沃尔杯经过了三天的鏖战后落幕。尽管费德勒是本届拉沃尔杯的最大话题,但这项赛事还是在这三天的对决当中产生了一个新的纪录,在最后一个比赛日当中,21汤普森库里能打到40岁,五冠是历史最佳球员的标杆勇士球员克雷汤普森今日接受了采访。汤普森说我们为取得成就感到骄傲,但那都是过去。伟大的球队保持饥饿,我们所有人都有再拿一冠的动力。健康的进入新赛季,我每天想到它(第5次夺冠的机会)囧叔救命稻草!小基耶萨成替补席的核武器,天使若离开格子将取代阿莱格里新赛季执教尤文的成绩不佳,目前尤文在意甲和欧冠赛场上的成绩都不是太让人满意,高层方面内德维德再次高举反囧大旗,虽然2019年阿莱格里就曾尝试过轰走阿莱格里,但是去年夏天囧叔女人想年轻,不要乱穿衣!看董卿的秋装造型,48岁穿出28岁的状态女人,或许是世界上最怕老的一种生物。她们对于谈论自己的年龄话题尤为敏感,面对因衰老导致的容貌身材问题也非常介意,可以说爱美是女人的天性,怕老也是!因此,上了年纪的女人就会通过穿衣打广东宏远弃将重返CBA!一年无球可打,加盟四川男篮自由球员这个窗口期无法重返CBACBA只有两个注册期,今年的8月1日8月31日,这个注册期已经过了。第二个注册窗口期一般是常规赛进行到三分之二场次时开启,具体起止时间CBA官方还未卵巢保养真的有用吗?这些坑别再踩了卵巢对女性来说非常重要,它能掌控生育功能,调节月经周期,还影响着皮肤和身材,可以说,女性皮肤好不好身材好不好月经是否正常能否孕育一个健康的宝宝,都和卵巢有关。一般情况下,女性在4076岁老人坦言晚年的因果,其实在50岁左右就已经安排好了曾志强教授曾说过做事要趁早,晚了才抱佛脚,佛一脚将你踢开。尘世间万事万物都有因果,年轻时种下了这个因,那晚年就只能得到相对应的果。没有人,能够置身事外。生活里,我们常听到这样一句话苗疆巫蛊苗族人真的会下蛊吗?中蛊后如何解除旅游文化民族文化贵州苗族巫蛊黔东南写在前面的话民族文化习俗总是给人以神秘的色彩,在贵州黔东南这片土地,由于它的偏远与贫瘠,让很多民族文化得以沿袭传承。苗族的巫蛊,一直很令人迷幻,在阿波罗计划的可怕真相是什么?潜伏在月球上的是谁?1961年,美国总统肯尼迪计划在10年内,一定要让人类登上月球,推动了阿波罗计划。当时的议会没有对此进行充分的研究,就批准了阿波罗计划的实施。阿波罗计划20世纪50年代,当时的苏联Facebook母公司Meta宣布,将裁员1。1万人Meta宣布将裁员1。1万人中新社旧金山11月9日电当地时间9日,美国社交网络巨头Facebook母公司Meta宣布,将裁员1。1万人。Meta首席执行官马克扎克伯格在当日写给员工国家统计局10月份工业生产者出厂价格同比下降1。3环比上涨0。2央视网消息据国家统计局网站,2022年10月份,全国工业生产者出厂价格同比下降1。3,环比上涨0。2工业生产者购进价格同比上涨0。3,环比上涨0。3。110月平均,工业生产者出厂价高成长企业论科技企业的成长需要投资机构长期陪伴松禾资本创始合伙人罗飞如是说南方财经全媒体记者袁新韫实习生谭颖怡刘雅文深圳报道今年6月,深圳发布了深圳市人民政府关于发展壮大战略性新兴产业集群和培育发展未来产业的意见,其中20个战略性新兴产业重点细分领域和8龙虎榜丨超讯通信今日涨停,营业部席位合计净买入1805。84万元11月10日,超讯通信今日涨停,龙虎榜数据显示,上榜营业部席位全天成交7702。73万元,占当日总成交金额比例为31。58。其中,买入金额为4754。28万元,卖出金额为2948。个体户成立后,你需要考虑什么?成立个体户之前,除了依据实务定好经营范围之外,还会着重考虑纳税的多少,如果挣得很多,实际拿到手里钱却很少的话,那就对不起自己的辛苦与担当的创业风险了。小李开了一个小餐馆,早出晚归半关于延期还贷,河南21家银行最全政策梳理来了大河报大河财立方(记者裴熔熔徐曼丽席韶阳)受疫情影响无法按时还贷款怎么办?在严峻复杂的疫情形势下,正常还贷成了不少企业及个人的难题,延期还贷相关政策是否持续,成为社会关注的热点。针