问题 抛出异常的方法如何内联?


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


10200
2017-08-28 01:55


起源

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


答案:


你设想的问题是什么?由于它是JVM本身进行内联,所以没有什么可以阻止它在构造堆栈跟踪以安装在Throwable对象中时记住它内联的位置并对此进行更正。

当有例外时 抛出构建后,JVM将遍历CPU堆栈并确定每个机器堆栈帧是否对应于解释的字节码,JITted代码,来自库的本机代码等等。为此,它指的是表示机器代码中哪些地址对应于字节码中的哪些指令(以及进一步返回源行,如果该类信息存在于类文件中)的表。该表可以很好地指定JITted代码中的某个位置可以对应多个Java级堆栈帧。

但是,JVM不是 需要 去做这个。它也可以简单地选择构造具有神秘中断的堆栈轨迹。见 用于Throwable.getStackTrace()的javadoc。 (甚至不要求JVM能够产生堆栈跟踪 一点都不)。


10
2017-08-28 02:38





你可能想看看 这个文件 这解释了异常处理在JVM中的工作原理:

每种方法都可以   捕获异常与异常表相关联   在类文件中传递的字节码序列   方法。异常表为每个异常都有一个条目   被每个尝试块捕获。每个条目有四条信息:   起点和终点,字节码序列中的pc偏移量   跳转到,以及异常类的常量池索引   被抓住了


3
2017-08-28 02:18



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