什么是虚拟机栈_栈帧

2023-11-21 18:51:14 浏览数 (1)

局部变量表

这是变量值的存储空间,用于存放方法参数和方法内部定义的局部变量。 在 Java 编译成 Class 文件时,就在方法的 Code 属性的 MAX_LOCALS 数据项中确定该方法需要分配的最大局部变量表的容量。这个区域,以 Slot 为最小单位,32 位虚拟机,一个 slot 可以放 32 位(4字节)以内的数据。如果是 64 位,虚拟机就会以高位对其方式,分配两个连续的 slot 空间,相当于把一次 long 和 double 数据类型,读写分割成为两次 32 位读写。 Slot 对对象的引用会影像 GC,如果被引用,将不会被回收。

操作数栈

与局部变量表一样,在编译时期就确定了该方法所需要分配的局部变量表的最大容量。操作数栈的每一个元素可以是任意的 Java 数据类型。当一个方法刚执行时,这个方法的操作数栈是空的,在方法执行的过程中,会有各种字节码指令往操作数栈中写入和提取内容,也就是出栈/入栈操作。

一般来讲,栈帧之间都是独立的,但是大多虚拟机都会做优化,使局部变量表和操作数栈之间有重叠,以达到共用的目的,这样能节省额外的参数复制等工作,重叠过程类似下图。

动态连接

每个栈帧都包含一个指向运行时常量池中该栈帧所属方法的引用,Class 文件的常量池中存有大量的符号引用。字节码中的方法调用指令就以常量池中方法的符号引用为参数。这些符号引用一部分会在类加载的时候,或者第一次使用的时候转化为直接引用(静态方法,似有方法等),这种转化成为静态解析。另一部分将在每一次运行期间转化为直接引用。这部分称之为动态连接。

方法返回地址

当一个方法开始执行后,有以下两种方式来退出

  1. 执行引擎遇到任意一个方法返回的字节码指令:传递给上层的方法调用者,是否有返回值和返回值类型将根据遇到何种方法来返回指令决定,这种退出的方法成为正常完成出口。
  2. 在方法的执行中遇到异常:无论是java虚拟机内部产生的异常还是代码中thtrow出的异常,只要在本方法的异常表中没有搜索到匹配的异常处理器,就会导致方法退出,这种退出的方式称为异常完成出口,一个方法若使用该方式退出,是不会给上层调用者任何返回值的。无论使用那种方式退出方法,都要返回到方法被调用的位置,程序才能继续执行。方法返回时可能会在栈帧中保存一些信息,用来恢复上层方法的执行状态。一般方法正常退出的时候,调用者的pc计数器的值可以作为返回地址,帧栈中很有可能会保存这个计数器的值作为返回地址。方法退出的过程就是栈帧在虚拟机栈上的出栈过程,因此退出时的操作可能有:恢复上层方法的局部变量表和操作数栈,把返回值压入调用者的操作数栈每条整pc计数器的值指向调用该方法的后一条指令。

说人话:方法返回地址主要存放调用该方法的 PC 寄存器的值(程序计数器),方法无论是通过正常还是异常退出,都应该返回该方法被调用的位置,正常退出是,调用 PC 计数器的值作为返回地址,即调用该方法的指令的下一条指令地址。如果异常退出的话,返回地址是通过异常表来确定,栈帧中一般不会保存这部分信息。这两个出口的区别就在于,异常完成出口退出是不会给上一层调用者产生任何返回值的。

我正在参与2023腾讯技术创作特训营第三期有奖征文,组队打卡瓜分大奖!

0 人点赞