抛出异常的方法如何进行内联处理?

10

我很好奇Java JVM如何可能内联可能会抛出异常的方法。我认为至少可以内联一些这样的方法(例如那些具有数组访问权限并因此可能抛出ArrayIndexOutOfBoundsException的方法)。我看到的问题是,如果实际上发生异常,如何显示正确的堆栈跟踪,如果您已经内联了该方法?由于不同的方法可以在不同的机器上进行内联,因此内联不会破坏堆栈跟踪机制吗?


2
在C++中,内联几乎可以保证堆栈信息的丢失。事实上,异常堆栈跟踪缺少一个帧并不是世界末日,这只是内联的一个已接受的后果之一(也是编译器提供调试模式选项以抑制所有内联的原因之一)。我不知道Java是否行为相同。 - Marcelo Cantos
我本意是提出一个Java问题,但了解一下C++中的工作原理也很有趣。 - Gravity
2个回答

10

您预见到的问题是什么?由于执行内联的是JVM本身,因此没有任何防止它记住它内联的位置并在构造要安装到Throwable对象中的堆栈跟踪时进行修正的东西。

当构造异常时,JVM将遍历CPU堆栈并确定每个机器堆栈帧是否对应于解释的字节码、JIT编译的代码、来自库等的本地代码。为此,它参考表格,告诉哪些机器代码地址对应于字节码中的哪些指令(如果类文件中存在该信息,则进一步返回源代码行)。这个表可以很好地指定JIT编译的代码中的某个位置可以对应于多个Java级别的堆栈帧。

但是,JVM不一定需要这样做。它也可以选择仅构造具有神秘断点的堆栈跟踪。请参见 Throwable.getStackTrace() 的javadoc。(甚至没有要求JVM能够完全产生堆栈跟踪)。


3

您可能想查看此文档,该文档解释了JVM中异常处理的工作原理:

每个捕获异常的方法都与一个异常表相关联,该表随着方法的字节码序列一起在类文件中提供。异常表为每个try块捕获的每个异常都有一个条目。每个条目包含四个信息:开始和结束点、要跳转到的字节码序列中的pc偏移量以及正在被捕获的异常类的常量池索引。


我很感兴趣去查看一下。不过,我特别想了解内联与异常的交互作用。如果一个函数被内联,堆栈跟踪信息应该会丢失,但在Java程序中似乎并非如此。 - Gravity
1
请记住,在Java中的内联是在运行时进行的,而不像C/C++那样在编译时进行,因此您不会“丢失”任何信息。任何被优化掉并需要检索的信息都可以存储在查找/跳转表中。 - jonathan.cone
将异常信息存储在查找表中,是否会导致无法接受的性能问题,特别是对于像ArrayIndexOutOfBounds这样非常常见的异常而言? - Gravity

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接