8

据我了解,throw是一个原始的 jvm 命令。当它被调用时,JVM“检查当前调用堆栈是否可以捕获它”。如果不能,那么 java 几乎就像调用 return 一样简单地弹出调用堆栈。然后jvm“检查当前调用堆栈是否可以捕获它”等等递归。

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

4

2 回答 2

9

JVM 规范对此有详细说明。

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

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

于 2012-10-31T23:20:12.160 回答
1

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

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

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

如果在表中未找到“匹配”,则调用堆栈实际上被“弹出”,将下一个较早的方法放在堆栈顶部,并且上述在较早方法的 try/catch 表中搜索“匹配”范围重复。

这当然是过于简单化了。处理范围涉及很多额外的逻辑finally,例如,和几个“边缘”情况。

于 2014-07-29T02:56:26.503 回答