今天,简单讲讲android里使用try--catch语句是否会影响性能。

我在app的代码里有一些for循环里面有try - catch语句,担心循环里一直执行try - catch语句会影响效率,所以在网上查询了资料,后来发现并不影响性能。这里记录一下。

1、JAVA性能调优-将try/catch块移出循环

据说把try/catch块放入循环体内,会极大的影响性能。因为使用了try/catch模块的使用,会让JAVA虚拟机做很多额外的工作。就好比对每个人说,“嗨,哥们,路上可能有蛇。于是听到的人只好手拿木棍,小心翼翼的往前走”。

把try/catch块放到循环外面,就好比对一大群人说,“嗨,兄弟们,路上可能有蛇。于是听到的人安排部分人员拿木棍往前走,其他人基本不受影响”

这个理论蛮不错的,测试下对性能的实际影响

2、将try/catch块在循环条件进行比对的源代码

package com.java.test;import java.util.ArrayList;import java.util.List;/*** 使用预热模式 JVM参数:-XX:PrintCompilation* 目标:测试在循环中使用try/catch对性能的影响* */public class EasyTryCatchTest {List<String>aList = new ArrayList<String>();public staticvoid main(String[] args) throws Exception {intwarmUpCycles = 10000000; // 预热次数inttestCycles   = 50000000; // 正式执行次数EasyTryCatchTestse = new EasyTryCatchTest();System.out.println("...预热循环开始 ...");longcatchTime = se.runCatchLoop(warmUpCycles);longnotcatchTime = se.runCatchNotLoop(warmUpCycles);System.out.println("...预热结束");System.out.println("...预热阶段,try/catch在循环中耗时: " + catchTime);System.out.println("...预热阶段,try/catch不在循环中耗时: " + notcatchTime);System.out.println("...进入正式循环 ...");catchTime =se.runCatchLoop(testCycles);notcatchTime= se.runCatchNotLoop(testCycles);System.out.println("...正式运行阶段,try/catch在循环中耗时: " + catchTime);System.out.println("...正式运行阶段,try/catch不在循环中耗时: " + notcatchTime);}publicEasyTryCatchTest(){aList.add("0");}// try / catch 在具体的循环体(内圈 循环 )中private longrunCatchLoop(int iterations) {// 开始计时longstartTime = System.nanoTime();for (intloop = 0; loop < iterations; loop++) {try {Stringtemp = aList.get(0);} catch(Exception e) {}}// 计时完成longelapsedTime = System.nanoTime();return(elapsedTime - startTime);}// try / catch 在不在具体的循环体(内圈 循环 )中public longrunCatchNotLoop(int iterations) {// 开始计时longstartTime = System.nanoTime();try {for (intloop = 0; loop < iterations; loop++) {Stringtemp = aList.get(0);}} catch(Exception e) {}// 计时完成longelapsedTime = System.nanoTime();return(elapsedTime - startTime);}}

3、运行结果

...预热循环开始 ...

...预热结束

...预热阶段,try/catch在循环中耗时: 76507316

...预热阶段,try/catch不在循环中耗时: 76292613

...进入正式循环 ...

...正式运行阶段,try/catch在循环中耗时: 389151690

...正式运行阶段,try/catch不在循环中耗时: 389874615

4、结论

从测试结果来看,可能我们的JDK(1.6)会自动优化字节码的缘故,因此try/catch是否在循环中,对整体性能的影响几乎微乎其微,389151690 389874615 差距非常的小。

以上是没有发生异常的情况,如果发生异常,那么也就无法比较了。

这里再举一个例子:

讨论的问题

当时讨论的是这样的问题:
比较下面两种try catch写法,哪一种性能更好。

   for (int i = 0; i < 1000000; i++) {try {Math.sin(j);} catch (Exception e) {e.printStackTrace();}
}
try {for (int i = 0; i < 1000000; i++) {Math.sin(j);}} catch (Exception e) {e.printStackTrace();}

结论

在没有发生异常时,两者性能上没有差异。如果发生异常,两者的处理逻辑不一样,已经不具有比较的意义了。

分析

要知道这两者的区别,最好的办法就是查看编译后生成的Java字节码。看一下try catch到底做了什么。
下面是我的测试代码

import org.openjdk.jmh.annotations.Benchmark;/*** Created by kevin on 16-7-10.*/
public class ForTryAndTryFor {public static void main(String[] args) {tryFor();forTry();}public static void tryFor() {int j = 3;try {for (int i = 0; i < 1000; i++) {Math.sin(j);}} catch (Exception e) {e.printStackTrace();}}public static void forTry() {int j = 3;for (int i = 0; i < 1000; i++) {try {Math.sin(j);} catch (Exception e) {e.printStackTrace();}}}
}

使用javap -c fileName.class输出对应的字节码

Compiled from "ForTryAndTryFor.java"
public class com.kevin.java.performancetTest.ForTryAndTryFor {public com.kevin.java.performancetTest.ForTryAndTryFor();Code:0: aload_01: invokespecial #1                  // Method java/lang/Object."<init>":()V4: returnpublic static void main(java.lang.String[]);Code:0: invokestatic  #2                  // Method tryFor:()V3: invokestatic  #3                  // Method forTry:()V6: returnpublic static void tryFor();Code:0: iconst_31: istore_02: iconst_03: istore_14: iload_15: sipush        10008: if_icmpge     2311: iload_012: i2d13: invokestatic  #4                  // Method java/lang/Math.sin:(D)D16: pop217: iinc          1, 120: goto          423: goto          3126: astore_127: aload_128: invokevirtual #6                  // Method java/lang/Exception.printStackTrace:()V31: returnException table:from    to  target type2    23    26   Class java/lang/Exceptionpublic static void forTry();Code:0: iconst_31: istore_02: iconst_03: istore_14: iload_15: sipush        10008: if_icmpge     3111: iload_012: i2d13: invokestatic  #4                  // Method java/lang/Math.sin:(D)D16: pop217: goto          2520: astore_221: aload_222: invokevirtual #6                  // Method java/lang/Exception.printStackTrace:()V25: iinc          1, 128: goto          431: returnException table:from    to  target type11    17    20   Class java/lang/Exception
}</init>

指令含义不是本文的重点,所以这里就不介绍具体的含义,感兴趣可以到Oracle官网查看相应指令的含义The Java Virtual Machine Instruction Set
好了让我们来关注一下try catch 到底做了什么。我们就拿forTry方法来说吧,从输出看,字节码分两部分,code(指令)和exception table(异常表)两部分。当将java源码编译成相应的字节码的时候,如果方法内有try catch异常处理,就会产生与该方法相关联的异常表,也就是Exception table:部分。异常表记录的是try 起点和终点,catch方法体所在的位置,以及声明捕获的异常种类。通过这些信息,当程序出现异常时,java虚拟机就会查找方法对应的异常表,如果发现有声明的异常与抛出的异常类型匹配就会跳转到catch处执行相应的逻辑,如果没有匹配成功,就会回到上层调用方法中继续查找,如此反复,一直到异常被处理为止,或者停止进程。具体介绍可以看这篇文章How the Java virtual machine handles exceptions
所以,try 在反映到字节码上的就是产生一张异常表,只有发生异常时才会被使用。由此得到出开始的结论。
这里再对结论扩充:
try catch与未使用try catch代码区别在于,前者禁止try语句块中的代码进行优化,例如重排序,try catch里面的代码是不会被编译器优化重排的。对于上面两个函数而言,只是异常表中try起点和终点位置不一样。至于刚刚说到的指令重排的问题,由于for循环条件部分符合happens- before原则,因此两者的for循环都不会发生重排。当然只是针对这里而言,在实际编程中,还是提倡try catch范围尽量小,这样才可以充分发挥java编译器的优化能力。

至于网上得出的for-try比try-catch要快是由于cpu执行代码时可能有环境的影响因素,因为手机可能同时执行其他线程,所以测试的时间不准确。具体来说:

原因至少有下面这些:System.currentTimeMillis()测量的只是逝去的时间,并没有反映出cpu执行该函数真正消耗的时间。
这导致线程未被分配cpu资源时,等待cpu的时间也会被计算进去

JIT优化导致结果出现偏差。
像这种多次循环非常容易触发JIT的优化机制,关于JIT,这里简短的介绍一下

在Java编程语言和环境中,即时编译器(JIT compiler,just-in-time compiler)是一个把Java的字节码(包括需要被解释的指令的程序)转换成可以直接发送给处理器的指令的程序。当你写好一个Java程序后,源语言的语句将由Java编译器编译成字节码,而不是编译成与某个特定的处理器硬件平台对应的指令代码(比如,Intel的Pentium微处理器或IBM的System/390处理器)。字节码是可以发送给任何平台并且能在那个平台上运行的独立于平台的代码。

简单来说,JIT会将某些符合条件(比如,频繁的循环)的字节码被编译成目标的机器指令直接执行,从而加快执行速度。可以通过配置-XX:+PrintCompilation参数,观察JIT。当JIT执行优化时,会在终端输出相应的优化信息。

类加载时间也被统计进来了。
类首次被使用时,会触发类加载,产生了时间消耗。

由上面的分析不难看出为什么绝大多数时候tryFor会比forTry快了,JIT编译耗时和类加载时间会被统计到第一个执行的函数forTry里面。要验证这个也非常简单,把两个函数的调用顺序互换,然后再进行测试。
当然,还有一点不能忽略的是System.currentTimeMillis()并不是统计cpu真正执行时间,所以可能测试的结果会有出入。可以使用JProfiler配合Intellij IDEA进行测试,下面会提到。由于这些因素影响着测试结果,从而使得测试结果扑朔迷离

所以总结一下,在没有异常时,try-catch不影响性能,当发生异常时,才会有多余的消耗。

android try catch并不影响性能就讲完了。

就这么简单。



android try catch并不影响性能相关推荐

  1. 流言粉碎机:JAVA使用 try catch会影响性能

    流言粉碎机:JAVA使用 try catch会影响性能 一.JVM 异常处理逻辑 二.关于JVM的编译优化 1. 分层编译 2. 即时编译器 1. 解释模式 2. 编译模式 3. 提前编译器:jaot ...

  2. try catch真的会影响性能?居然被骗了好几年...

    一.JVM 异常处理逻辑 Java 程序中显式抛出异常由athrow指令支持,除了通过 throw 主动抛出异常外,JVM规范中还规定了许多运行时异常会在检测到异常状况时自动抛出(效果等同athrow ...

  3. try - catch 语句真的会影响性能吗?

    不知道从何时起,传出了这么一句话:Java中使用try catch 会严重影响性能.然而,事实真的如此么?我们对try catch 应该畏之如猛虎么? 一.JVM 异常处理逻辑 Java 程序中显式抛 ...

  4. 别被骗了,try-catch语句真的会影响性能吗?

    前言 不知道从何时起,传出了这么一句话:Java中使用try catch 会严重影响性能. 然而,事实真的如此么?我们对try catch 应该畏之如猛虎么? 一.JVM 异常处理逻辑 Java 程序 ...

  5. 支付宝二面:使用 try-catch 捕获异常会影响性能吗?90%都会答错

    不知道从何时起,传出了这么一句话:Java中使用try catch 会严重影响性能. 然而,事实真的如此么?我们对try catch 应该畏之如猛虎么? 一.JVM 异常处理逻辑 Java 程序中显示 ...

  6. 支付宝二面:使用 try-catch 捕获异常会影响性能吗?大部分人都会答错!

    不知道从何时起,传出了这么一句话:Java中使用try catch 会严重影响性能. 然而,事实真的如此么?我们对try catch 应该畏之如猛虎么? 一.JVM 异常处理逻辑 Java 程序中显式 ...

  7. union all会影响性能吗_Java 中的 try catch 影响性能吗?

    作者:陈树义来源:https://www.cnblogs.com/chanshuyi/p/is_try_catch_ineffective.html 前几天在 code review 时发现有一段代码 ...

  8. java try 性能损耗_Java 中的 try catch 影响性能吗?

    前几天在 code review 时发现有一段代码中存在滥用try catch的现象.其实这种行为我们也许都经历过,刚参加工作想尽量避免出现崩溃问题,因此在很多地方都想着 try catch一下. 但 ...

  9. Android MediaScanner MediaProvider流程以及性能优化,音视频扫描

    Android MediaScanner MediaProvider流程以及性能优化,音视频扫描 快速扫描 一.源码解析 github链接 MediaScanner时序图 MediaSacannerR ...

最新文章

  1. VTK:PolyData之PointLocatorVisualization
  2. Spring保存文件到MongoDB之GridFS支持
  3. 美图笔试算法题(两个人拿石头判断输赢)
  4. mooc- 基本程序设计方法week1,week2
  5. jQuery中each()的用法
  6. java bean spring_Java bean与Spring、Spring MVC关系
  7. 机器学习笔记(2):线性回归-使用gluon
  8. 微信小程序scroll-view去掉滚动条
  9. 字节流转换为对象的方法
  10. 运筹学matlab实验报告,运筹学上机实验报告 利用Matlab求解整数线性规划
  11. 64位 linux 中 oracle 11g dbca 报 out of memory 错误
  12. javascript实现图片轮播_手撸一个简易版轮播图(上)
  13. VRRP与VLAN综合实验
  14. NOIp 2014 #5 解方程 Label:数论?
  15. 用python建云盘_超简单!基于Python搭建个人“云盘”
  16. c++ Primer plus 之c++学习
  17. 测试u盘容量的软件哪家好,U盘容量检测工具
  18. C语言打印乘法口诀表
  19. ensp两个路由的配置(想对全世界说晚安 恰好你就是全世界)
  20. 抑制剧毒弧菌的新型噬菌体被发现

热门文章

  1. 论林耐斯-Linux系统的重要性
  2. 静态代理和JDK动态代理
  3. php之变量覆盖漏洞讲解
  4. D3DCOLOR与D3DXCOLOR
  5. 从实例到数理来解析感知机学习算法(PLA)
  6. 换Ubuntu邮件客户端Evolution为Thunderbird
  7. 201671010406 丁家辉《英文文本统计分析》结对项目报告
  8. 读spring源码(一)-ClassPathXmlApplicationContext-初始化
  9. 第11讲++数据的基本查询
  10. Oracle 11g 之自动收集统计信息