据我了解,throw
是一个主要的jvm命令。调用它时,JVM“检查当前调用堆栈是否可以捕获它”。如果它不能,那么java只是简单地弹出调用栈,就好像调用了一个返回一样。然后jvm“检查当前调用堆栈是否可以捕获它”,依此递归。
我的问题:JVM在算法上如何知道调用堆栈中哪些地方可以捕获给定的异常?每个调用堆栈条目中是否存储了元数据,将异常映射到代码块?堆中是否有一个静态数据结构以某种方式跟踪它?因为某处必须有数据跟踪。
答案 0 :(得分:9)
JVM specification有详细说明。
特别是,section 4.7.3提供了有关异常表的详细信息,该异常表是一系列条目,说明在哪些指令之间捕获了异常。 Section 3.12给出了一个具体的例子。
如何将此元数据映射到JIT的本机代码当然是另一回事 - 并且特定于实现。例如,可能会有一些映射从本机JITted代码中的每个指令位置返回到原始字节码位置,此时可以查询异常表以找到正确的处理程序。
答案 1 :(得分:1)
一般来说:当抛出异常时,JVM会提取"调用堆栈"。这标识了调用堆栈中每个级别正在执行的字节码或机器指令,以及与该位置关联的类和方法。
然后,对于堆栈中的每个方法(从发生异常并向后工作的方法开始),JVM在方法的表中查找(在内部类对象中)将try / catch范围映射到字节码/机器指令范围。
如果"匹配"在表的表中找到方法,抛出的异常类型是在找到的范围内监视的类,然后在将异常设置为某种参数后将控制转移到catch
入口点位置,以便catch
子句可以引用它。
如果"匹配"在表中找不到调用堆栈有效地弹出"将下一个早期方法置于堆栈顶部,并且上面搜索"匹配"在早期方法的try / catch范围表中重复。
这当然是一种过度简化。处理finally
范围涉及很多额外的逻辑,例如,几个" edge"案例。