try-catch影响性能吗?


try-catch会影响性能吗? try-catch放在循环块里面比放在外面程序运行会慢吗?
看到论坛上有人对try-catch对性能的影响存在疑问,比如:
http://www.iteye.com/topic/1127950
很多想当然的答案是: try-catch放在循环块里面肯定比放在循环块外面慢.
但是, 这个想当然的答案是错误的.

加了try-catch块的代码跟没有加的代码运行时的性能是一样的, 没有区别,
区别只是加了try-catch块的代码在抛出异常时, 会有不同的处理逻辑, 仅此而已.

stackOverflow的网站上有人也问过类似问题:
http://stackoverflow.com/questions/141560/should-try-catch-go-inside-or-outside-a-loop
老外回答的比较详细.

下面是我翻译的一篇解释JVM异常处理机制的文章, 原文来自:
http://www.javaworld.com/article/2076868/learn-java/how-the-java-virtual-machine-handles-exceptions.html

static int remainder(int dividend, int divisor) throws DivideByZeroException { try { return dividend % divisor; } catch (ArithmeticException e) { throw new DivideByZeroException(); } }



The main bytecode sequence for remainder: 0 iload_0// Push local variable 0 (arg passed as divisor) 1 iload_1// Push local variable 1 (arg passed as dividend) 2 irem// Pop divisor, pop dividend, push remainder 3 ireturn// Return int on top of stack (the remainder) The bytecode sequence for the catch (ArithmeticException) clause: 4 pop// Pop the reference to the ArithmeticException // because it isn't used by this catch clause. 5 new #5 // Create and push reference to new object of class // DivideByZeroException. DivideByZeroException 8 dup// Duplicate the reference to the new // object on the top of the stack because it // must be both initialized // and thrown. The initialization will consume // the copy of the reference created by the dup. 9 invokenonvirtual #9 ()V> // Call the constructor for the DivideByZeroException // to initialize it. This instruction // will pop the top reference to the object. 12 athrow// Pop the reference to a Throwable object, in this // case the DivideByZeroException, // and throw the exception.



JVM在执行try-catch的字节码的时候, 会维护一张异常表. 如果有异常发生, JVM会从异常表里面查询是否该异常能够被catch住. 每一个能捕获异常的方法都通过这个方法的字节码与它所属类的异常表关联. 每一处声明的try-catch异常都对应异常表中的一个条目.
每一个条目有四列信息: 异常声明的开始行, 结束行, 异常捕获后跳转到的代码计数器(PC)所指向的行数, 还有一个表示捕获的异常类的常量池索引.
异常表是类似于下面这样:
【try-catch影响性能吗?】
Exception table: fromtotarget type 044ArithmeticException>

上面的异常表表明从第0行到第3行(包括)能够捕获ArithmeticException.
try块的结束行在异常表的to这一列中表示, to所指的行数永远比能捕获异常代码的最后一行要大.
这个示例中try块结束行(to)为4, 但是能捕获异常的最大行数为从from(第0行)到最大行数为第3行, 这个范围是, 0到3的闭区间, 对应remainder字节码中的try块中的前4行.

这个表中Target列表示当ArithmeticException异常在0-3行被抛出时, 将会被捕获并跳转Target所指向的行数(注意这里只是一个
偏移地址, 不是真实代码行数).

如果在执行方法时有一个异常被抛出, JVM就会从异常表中按照条目所出现的顺序查找对应的条目. 如果异常抛出时PC计数器所指向的行数正好落在异常表中某一条目包含的范围内, 并且所抛出的异常正好是异常表中type列所指定的异常(或者所指定异常的子类), 那么JVM就会将PC计数器指向Target偏移量所指向的地址, (进入catch块)继续执行.

如果没有在异常表中找到异常, JVM就会将当前栈帧弹出并重新抛出这个异常. 当JVM弹出当前栈帧的时候, 它就会中止当前方法的执行, 返回到调用当前方法的外部方法中, 不过并不会像正常没有异常发生时那样继续执行外部方法, 而是在外部方法中抛出相同的异常, 这样将会导致JVM会在外部方法中重复查询异常表并处理异常的过程.

转自:http://ivarchen.iteye.com/blog/2090048

    推荐阅读