JVM如何知道在运行时捕获exception的位置?

根据我的理解, throw是一个灵长类似的jvm命令。 调用它时,JVM“检查当前调用堆栈是否可以捕获它”。 如果它不能,那么java只是简单地弹出调用栈,就像调用一个返回一样。 然后jvm“检查当前调用堆栈是否可以捕获它”等等递归。

我的问题:JVM在算法上如何知道调用堆栈中哪些地方可以捕获给定的exception? 每个调用堆栈条目中是否存储了元数据,将exception映射到代码块? 堆中是否有一个静态数据结构以某种方式跟踪它? 因为某处必须有数据跟踪。

JVM规范有关于此的详细信息。

特别是, 第4.7.3节提供了有关exception表的详细信息,该exception表是一系列条目,说明在哪些指令之间捕获了exception。 第3.12节给出了一个具体的例子。

这个元数据如何映射到JIT的本机代码当然是另一回事 – 而且是特定于实现的。 例如,可能会有一些映射从本机JITted代码中的每个指令位置返回到原始字节码位置,此时可以查询exception表以找到正确的处理程序。

一般来说:当抛出exception时,JVM会提取“调用堆栈”。 这标识了调用堆栈中每个级别正在执行的字节码或机器指令,以及与该位置相关联的类和方法。

然后,对于堆栈中的每个方法(从发生exception并向后工作的方法开始),JVM在方法的表中查找(在内部类对象中)将try / catch范围映射到字节码/机器指令范围。

如果在方法的表中找到“匹配”,并且抛出的exception类型是在找到的范围内监视的类,则在将exception设置为某种类型之后,控制将转移到catch入口点。参数位置所以catch子句可以引用它。

如果在表中找不到“匹配”,则调用堆栈实际上是“弹出”,将下一个早期方法置于堆栈顶部,并在上面的方法的try / catch表中搜索“匹配”范围重复。

这当然是一种过度简化。 在处理finally范围时涉及许多额外的逻辑,例如,和几个“边缘”情况。