阿里小哥带你玩转JVM:揭秘try-catch-finally在JVM底层都干了些啥?

做者:李瑞杰
目前就任于阿里巴巴,狂热JVM爱好者


让咱们准备一个函数:架构


而后,反编译他的字节码:jvm


首先咱们介绍异常表:在编译生成的字节码中,每一个方法都附带一个异常表。函数

异常表中的每个条目表明一个异常处理器,而且由 from 指针、to 指针、target 指针以及所捕获的异常类型构成。这些指针的值是字节码索引用以定位字节码。学习

下图就是我特别指出的JVM字节码中的异常表部分。线程

咱们来分析一下这几个语句的执行流程,首先执行:指针

这至关于执行:
cdn

再来:
blog

上图至关于执行
索引

有人问:try去哪了?
get

我立刻就要介绍。此时idiv执行完就有异常了,有异常了先找异常表。

我再贴一下异常表,他是怎么搜索的呢?

当程序触发异常时,Java 虚拟机会从上至下遍历异常表中的全部条目。

当触发异常的字节码的索引值在某个异常表条目的监控范围内,Java 虚拟机会判断所抛出的异常和该条目想要捕获的异常是否匹配。

若是匹配,Java 虚拟机会将控制流转移至该条目 target 指针指向的字节码。

咱们看 ,是第四个索引指向的字节码出了问题,显然,此时应该匹配红线这一条记录,从而跳转到第14个索引的字节码。

咱们看他怎么作的?

new出一个RuntimeException并抛出,它就是

这一句,按照咱们刚才的流程,此时依然须要找到这个RuntimeException在哪一个异常表的条目中

此时匹配到异常表的条目,跳转到字节码索引23

继续抛出RuntimeExcpetion,能够注意到 这实际上对应了

这个语句,因而咱们能够知道,在三个都出现异常的状况下,实际上最终向外抛出的异常是finally里面的异常。

能够看到当31索引处调用athrow语句抛出异常时,此时异常表没有任何一个条目可以匹配该异常,此时怎么办呢?

若是遍历完全部异常表条目,Java 虚拟机仍未匹配到异常处理器,那么它会弹出当前方法对应的 Java 栈帧,而且在调用者中重复上述操做。

在最坏状况下,Java 虚拟机须要遍历当前线程 Java 栈上全部方法的异常表。

事实上分析以上的总体的所有语句你能够发现,jvm层面有真正的finally吗?

没有

如今的作法是,复制 finally 代码块的内容,分别放在 try-catch 代码块全部正常执行路径以及异常执行路径的出口中。不管是否出现异常,确保必定会执行finally语句。

刚才catch出了异常,依然执行finally语句就能够发现这一点。至于其余路径,你们能够自行验证。我就在这里抛砖引玉了。

至于为何2-6发生任何异常都跳转到23?你们能够本身想一下这个问题。

我就提示一点 2-6 target为14的条目表明的catch是不能捕获全部异常的,可是你要确保finally的语句可以执行。而2-6恰巧是try语句块的内容。23这个索引恰巧是finally语句的一份复制。

END

我的公众号:石杉的架构笔记(ID:shishan100)

欢迎长按下图关注公众号:石杉的架构笔记!

公众号后台回复资料,获取做者独家秘制学习资料

石杉的架构笔记,BAT架构经验倾囊相授

相关文章
相关标签/搜索