从字节码角度理解JVM异常处理机制的原理
Posted TellH
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了从字节码角度理解JVM异常处理机制的原理相关的知识,希望对你有一定的参考价值。
前几天看到一条阿里巴巴的面试题:你了解try-catch块的实现原理吗?
我服,阿里的面试题就是有深度啊。要答好这一题,我觉得需要反编译一下.java源文件,因为字节码面前了无秘密。
反编译一段小程序
为了简单起见,我搞了一段没什么实际意义的try-catch示例代码。
public class Main
public static void main(String[] args)
int a = 1;
int b = 3;
try
b = a + b;
return;
catch (RuntimeException e1)
b = a - b;
catch (Exception e2)
b = a * b;
finally
a = 0;
通过命令javap -c Main 反编译.class文件得到一下输出:
public static void main(java.lang.String[]);
Code:
0: iconst_1
1: istore_1 // 给局部变量表1号slot赋值为1,代表a
2: iconst_3
3: istore_2 // 给局部变量表2号slot赋值为3,代表b
4: iload_1 // try块开始!
5: iload_2
6: iadd
7: istore_2 // 指令4-7 完成了操作:b = a + b
8: iconst_0 // finally块开始!
9: istore_1 // 指令8-9 完成操作a=0
10: return // 函数执行完毕,返回
11: astore_3 // RuntimeException e1异常处理块开始!
12: iload_1
13: iload_2
14: isub
15: istore_2
16: iconst_0 // finally处理块
17: istore_1
18: goto 38 // RuntimeException e1异常处理块结束!
21: astore_3 // Exception e2异常处理块开始!
22: iload_1
23: iload_2
24: imul
25: istore_2
26: iconst_0 // finally处理块
27: istore_1
28: goto 38 // Exception e2 异常处理块结束!
31: astore 4 // 其他任何异常处理块
33: iconst_0
34: istore_1
35: aload 4
37: athrow // 往将异常外抛
38: return
Exception table: // 异常表
from to target type
4 8 11 Class java/lang/RuntimeException //4-8 号指令中,碰到 NullPointerException时,跳到 11 号指令
4 8 21 Class java/lang/Exception
4 8 31 any
11 16 31 any
21 26 31 any
31 33 31 any
以上指令的注释是我加上去的,请大家对照源码加以理解。
总结
如果大家看完之后仍然有点模糊,相信看了下图后会对try-catch代码对应的字节码指令结构有一个全面的理解。
try块的范围就是体现在异常表行记录的起点和终点。JVM 在 try 住的代码区间内如有异常抛出的话,就会在当前栈桢的异常表中,找到匹配类型的异常记录的入口指令号,然后跳到该指令处执行。异常指令块执行完后,再回来继续执行后面的代码。JVM 按照每个入口在表中出现的顺序进行检索,如果没有发现匹配的项,JVM 将当前栈帧从栈中弹出,再次抛出同样的异常。当 JVM 弹出当前栈帧时,JVM 马上终止当前方法的执行,并且返回到调用本方法的方法中,但是并非继续正常执行该方法,而是在该方法中抛出同样的异常,这就使得 JVM 在该方法中再次执行同样的搜寻异常表的操作。
以上是关于从字节码角度理解JVM异常处理机制的原理的主要内容,如果未能解决你的问题,请参考以下文章
jvm原理(30)通过字节码分析this关键字以及异常表的重要作用&通过字节码分析Java异常处理机制
耗时一周深入理解JVM虚拟机异常处理字节码性能优化,全网最全面的JVM原理通俗易懂(强烈建议收藏)