前面一篇文章介绍了Java中异常的try-catch-final的原理(从字节码开始讲JVM是如何进行Java异常处理的(上)),今天我们就进一步分析一下JVM是如何实现它的。
JVM是如何抛异常的
要想了解try-catch-final的实现原理,那么就必须要先知道JVM是如何抛出异常信息的。以如下的代码为例来分析一下:
这段代码通过javap命令得到如下信息
代码很简单,对应的字节码也是非常的简单。看指令名称我们就可以很快的找到对应抛异常的指令:athrow指令。
athrow指令之前就是new 一个exception的代码,之后就是catch的代码了(从异常信息表里也能印证)。
知道了JVM是通过athrow指令来抛出异常的,接下来我们就看看JVM是如何实现athrow指令的。
athrow指令的实现原理
以JDK9为例,我们在JVM源码中全局搜索athrow,能够得到如下的信息:
从文件名就知道,athrow在不同的平台具有不同的实现。其实他们的实现基本大同小异,最终都是会跳到Interpreter::throw_exception_entry()返回的抛异常入口代码。
throw_exception_entry()返回的是指令模板(什么是JVM的指令模板呢?以后有机会再介绍),实现如下:
上面的代码主要实现的逻辑为:
说明:
- 显然查找异常处理代码是整个过程最为重要的部分,它是通过call_VM指令完成的,我们等会进一步说明。
- 查找到的异常处理代码是通过jmp指令跳转的,所以处理完是不会回到原位的,这也就实现了异常后面的代码是不会被处理的。
至此,JVM抛异常的实现原理就基本介绍完了,接下来介绍JVM是如何实现对异常的catch的。
JVM是如何实现catch异常的
知道了JVM是如何实现throw的,那么catch的实现过程也就很好理解了。我们知道Java方法抛出的异常catch和finally语句块都会被记录在异常信息表中,并且它们两的实现上并没有本质的区别。上面也介绍了JVM在实现抛异常的时候,会先去查找异常的处理代码位置,JVM就是在这个异常信息表中查找的。
JVM查找异常处理handler的代码比较多就不贴全部代码了,主要实现过程如下图所示:
其中最为关键的handler查找代码:
这段代码会循环遍历异常信息表,然后找到当前执行位置在起始和结束位置之间的那一项,接下来判断这一项是否能够处理需要处理的exception。