据我了解,throw
是一个原始的 jvm 命令。当它被调用时,JVM“检查当前调用堆栈是否可以捕获它”。如果不能,那么 java 几乎就像调用 return 一样简单地弹出调用堆栈。然后jvm“检查当前调用堆栈是否可以捕获它”等等递归。
我的问题:JVM 如何在算法上知道调用堆栈中的哪个位置可以捕获给定的异常?每个调用堆栈条目映射异常到代码块中是否存储元数据?堆中是否有一个静态数据结构以某种方式跟踪这一点?因为某处必须有数据来跟踪它。
据我了解,throw
是一个原始的 jvm 命令。当它被调用时,JVM“检查当前调用堆栈是否可以捕获它”。如果不能,那么 java 几乎就像调用 return 一样简单地弹出调用堆栈。然后jvm“检查当前调用堆栈是否可以捕获它”等等递归。
我的问题:JVM 如何在算法上知道调用堆栈中的哪个位置可以捕获给定的异常?每个调用堆栈条目映射异常到代码块中是否存储元数据?堆中是否有一个静态数据结构以某种方式跟踪这一点?因为某处必须有数据来跟踪它。
一般来说:当抛出异常时,JVM 会提取“调用堆栈”。这标识了在调用堆栈的每个级别上正在执行的字节码或机器指令,以及与该位置关联的类和方法。
然后,对于堆栈中的每个方法(从发生异常的方法开始并向后工作),JVM (在内部类对象中)查看方法的表,将 try/catch 范围映射到字节码/机器指令范围。
如果在表中找到方法的“匹配”,并且抛出的异常类型是在找到的范围内监视的类,则catch
在将异常设置为某种参数后,控制权将转移到入口点位置,以便catch
子句可以引用它。
如果在表中未找到“匹配”,则调用堆栈实际上被“弹出”,将下一个较早的方法放在堆栈顶部,并且上述在较早方法的 try/catch 表中搜索“匹配”范围重复。
这当然是过于简单化了。处理范围涉及很多额外的逻辑finally
,例如,和几个“边缘”情况。