try-catch影响性能吗?

本文探讨了try-catch语句对程序性能的影响,并通过JVM字节码层面解析了其执行机制,指出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 <Class DivideByZeroException>
                           // 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 <Method DivideByZeroException.<init>()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)所指向的行数, 还有一个表示捕获的异常类的常量池索引.

异常表是类似于下面这样:

 

Exception table:
   from   to  target type
     0     4     4   <Class java.lang.ArithmeticException>

上面的异常表表明从第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会在外部方法中重复查询异常表并处理异常的过程.

 

 

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值