首页 > 编程知识 正文

java方法调用栈,深入理解java虚拟机

时间:2023-05-04 15:52:53 阅读:25476 作者:3590

文章: http://www.tui cool.com/articles/urzrmnb

jvm为每个新创建的线程分配一个堆栈。 堆栈以帧为单位保存线程的状态。 jvm只对堆栈执行两种操作:逐帧堆栈操作和堆栈操作。

堆栈帧是用于支持虚拟机方法调用和方法执行的数据结构,虚拟机运行时数据区中虚拟机堆栈的堆栈堆栈框架包含方法的局部变量表、操作数堆栈、动态连接和方法返回地址等信息。 第一种方法对应于堆栈帧在虚拟机堆栈中从堆栈进入堆栈的过程,从调用开始到执行完成。

每个堆栈框架都包含局部变量表、操作数堆栈、动态连接、方法返回地址和其他信息。 编译代码时,堆栈帧需要多少本地变量表,完全确定多少深的操作数堆栈,并写入方法表的Code属性,因此需要为一个堆栈帧分配多少内存

一个线程中的方法调用链可能很长,许多方法同时处理执行状态。 对执行引擎来说,在活动线程中,只有虚拟机堆栈的第一个堆栈帧是有效的,被称为当前堆栈帧,与该堆栈帧相关联的方法是当前方法执行引用所执行的所有字节码指令只对当前堆栈帧起作用。 堆栈框架的概念结构如下图所示。

1 .局部变量表

局部变量表是一组变量值存储区,用于存储方法参数和方法内部定义的局部变量。 将Java程序编译为Class文件时,方法表中Code属性的max_locals数据项确定必须分配给该方法的局部变量表的最大容量。

执行方法时,虚拟机使用本地变量表完成参数变量列表的传递。 对于实例方法,局部变量表中0位索引的Slot缺省情况下是传递该方法所属的对象实例的引用。 方法可以使用关键字“this”访问此隐式参数。 其余参数按参数列表顺序排列,占用从1开始的局部变量Slot,参数表分配完成后,局部变量表的Slot按照方法主体内部定义的变量顺序可重用,方法主体定义的变量如果当前字节码PC计算机的值超出了某个变量的范围,则对应于该变量的Slot可以传递给另一个变量。

局部变量不像前面说明的类变量那样具有“准备阶段”。 类变量有两个赋予初始值的过程,一个是准备阶段,给系统赋予初始值; 另外,在初始化阶段,给程序员定义的值。 因此,在初始化阶段,程序员可以不为类变量赋值。 类变量还有一个确定的初始值。 但是,局部变量不同。 如果定义了局部变量,但未分配初始值,则无法使用。

2 .操作数堆栈

操作数堆栈也称为操作堆栈,它是先进先出堆栈。 与局部变量表一样,操作数堆栈的最大深度也在编译时写入方法表Code属性的max_stacks数据项中。 操作数堆栈中的每个元素可以是任何Java数据类型,包括长整型和双精度。 32位数据类型的堆栈容量为1,64位数据类型的堆栈容量为2。 堆栈容量的单位为“字宽”,对于32位虚拟机,“一个字宽”占4字节,对于64位虚拟机,“一个字宽”占8字节。

方法刚执行时,该方法的操作数堆栈为空,在方法执行过程中,有多种字节码指向操作数堆栈写入和提取值,即堆栈入和堆栈出操作。 例如,进行算术运算时操作操作数堆栈进行,或者调用其他方法时操作操作数堆栈传递参数。

另外,在概念模型中,两个堆栈帧作为虚拟机堆栈的要素,是完全独立的,但在大多数虚拟机的实现中,都进行了优化处理,以使两个堆栈帧部分重叠。 将下面堆栈帧的操作数堆栈的一部分与上面堆栈帧的局部变量表的一部分重叠,以便在返回方法调用时共享部分数据,而无需进行其他参数复制。 重叠过程如下图所示。

3 .动态连接

每个堆栈帧都包含对运行时常量池中该堆栈帧所属性的方法的引用,以支持方法调用期间的动态连接。 Class文件中的常量池有许多符号引用,字节码中的方法调用指令以对常量池中方法的符号引用为参数。 其中一些符号引用在类加载阶段或首次使用时直接转换为引用。 这个变换称为静态分析。 其他部分将在每个执行期间直接转换为引用。 这一部分称为动态连接。

4 .方法返回地址

一个方法执行后,用两种方法退出这个方法。 第一种方法是执行引擎检测到从其中一个方法返回的字节码指令。 在这种情况下,返回值可能传递给更高级别的方法调用方。 调用当前方法的方法称为调用方。 返回值和返回值的类型取决于哪个方法返回指令。 该退出方法称为“正常退出出口”。

另一种退出方法是在方法执行过程中引发异常,并且该异常未在方法中处理,无论是在Java虚拟机内部引发的异常还是在代码中使用athrow字节码指令引发的异常,都与方法的异常表相匹配将该结束方法设定为异常结束出口(

rupt Method Invocation Completion)。一个方法使用异常完成出口的方式退出,是不会给它的调用都产生任何返回值的。

无论采用何种方式退出,在方法退出之前,都需要返回到方法被调用的位置,程序才能继续执行,方法返回时可能需要在栈帧中保存一些信息,用来帮助恢复它的上 层方法的执行状态。一般来说,方法正常退出时,调用者PC计数器的值就可以作为返回地址,栈帧中很可能会保存这个计数器值。而方法异常退出时,返回地址是 要通过异常处理器来确定的,栈帧中一般不会保存这部分信息。

方法退出的过程实际上等同于把当前栈帧出栈,因此退出时可能执行的操作有:恢复上层方法的局部变量表和操作数栈,把返回值(如果有的话)压入调用都栈帧的操作数栈中,调用PC计数器的值以指向方法调用指令后面的一条指令等。

5. 附加信息

虚拟机规范允许具体的虚拟机实现增加一些规范里没有描述的信息到栈帧中,例如与高度相关的信息,这部分信息完全取决于具体的虚拟机实现。在实际开发中,一般会把动态连接,方法返回地址与其它附加信息全部归为一类,称为栈帧信息。

版权声明:该文观点仅代表作者本人。处理文章:请发送邮件至 三1五14八八95#扣扣.com 举报,一经查实,本站将立刻删除。