我很好奇Java JVM如何可能内联可能会抛出异常的方法。我认为至少可以内联一些这样的方法(例如那些具有数组访问权限并因此可能抛出ArrayIndexOutOfBoundsException
的方法)。我看到的问题是,如果实际上发生异常,如何显示正确的堆栈跟踪,如果您已经内联了该方法?由于不同的方法可以在不同的机器上进行内联,因此内联不会破坏堆栈跟踪机制吗?
我很好奇Java JVM如何可能内联可能会抛出异常的方法。我认为至少可以内联一些这样的方法(例如那些具有数组访问权限并因此可能抛出ArrayIndexOutOfBoundsException
的方法)。我看到的问题是,如果实际上发生异常,如何显示正确的堆栈跟踪,如果您已经内联了该方法?由于不同的方法可以在不同的机器上进行内联,因此内联不会破坏堆栈跟踪机制吗?
您预见到的问题是什么?由于执行内联的是JVM本身,因此没有任何防止它记住它内联的位置并在构造要安装到Throwable对象中的堆栈跟踪时进行修正的东西。
当构造异常时,JVM将遍历CPU堆栈并确定每个机器堆栈帧是否对应于解释的字节码、JIT编译的代码、来自库等的本地代码。为此,它参考表格,告诉哪些机器代码地址对应于字节码中的哪些指令(如果类文件中存在该信息,则进一步返回源代码行)。这个表可以很好地指定JIT编译的代码中的某个位置可以对应于多个Java级别的堆栈帧。
但是,JVM不一定需要这样做。它也可以选择仅构造具有神秘断点的堆栈跟踪。请参见 Throwable.getStackTrace() 的javadoc。(甚至没有要求JVM能够完全产生堆栈跟踪)。
您可能想查看此文档,该文档解释了JVM中异常处理的工作原理:
每个捕获异常的方法都与一个异常表相关联,该表随着方法的字节码序列一起在类文件中提供。异常表为每个try块捕获的每个异常都有一个条目。每个条目包含四个信息:开始和结束点、要跳转到的字节码序列中的pc偏移量以及正在被捕获的异常类的常量池索引。