0%

JAVA-栈与栈帧

栈(虚拟机栈VM Stack)

堆是存储的单元(堆只保存对象信息),栈是运行时的单位;在整个JVM的内存之中,栈内存是一个非常重要的的概念;栈里面存储的都是与当前线程相关的信息,包括:局部变量、程序运行状态、方法返回地址等。

虚拟机栈

栈中保存的是一个又一个栈帧

栈帧入栈与出栈

一个栈帧对应一个未运行完的函数;当某一个函数被调用一次时,就会产生一个栈帧(记录着该函数的相关信息),并入栈;当该函数运行完毕之后,其对应的栈帧会出栈。

注:函数的一次调用就会产生一个对应的栈帧,而不是一个函数本身对应一个栈帧;如:递归调用就会产生无数个栈帧。

栈的溢出

从栈的结构可知:如果栈帧数量过多(n多次调用方法)或某个(些)栈帧过大会导致栈溢出引发SOE(Stack Overflow Error)。

注:如果允许虚拟机栈动态扩展,那么当内存不足时,会导致OOM(OutOfMemoryError)

栈帧(Stack Frame)

栈帧是用于支持虚拟机进行方法调用和方法执行的数据结构。它是虚拟机运行时数据区的虚拟机栈的组成元素。调用一次方法(无论是不是调用的同一个方法)就会产生一个栈帧

操作数栈(Operand Stack)

表达式计算在操作数栈中完成。当一个方法刚刚开始执行的时候,这个方法的操作数栈是空的,在方法的执行过程中,会有各种字节码指令往操作数栈中写入和提取内容,也就是出栈/入栈操作。例如,在做算术运算的时候是通过操作数栈来进行的,又或者在调用其他方法的时候是通过操作数栈来进行参数传递的。

注:在概念模型里面,虚拟机栈中的栈帧之间是完全相互独立的。但是在大多数虚拟机的实现里都会做一些优化
处理,令两个栈帧出现一部分重叠。让下面栈帧的部分操作数栈与上面栈帧的部分局部变量表重叠在一起,
这样在进行方法的调用时就可以共用一部分数据,无需进行额外的参数复制传递,重叠的过程

局部变量表(Local Variable Table)

局部变量表是一组变量值存储空间,用于存放方法参数和方法内部定义的局部变量。

注:局部变量表以变量槽(solt)为最小单位,一个变量槽最大只允许保存四字节(即:32位)长度的变量。如果超过32位,
则会开辟两个连续的solt。

动态链接(Dynamic Linking)

请求方法时,先有动态链接,再包装为栈帧

每个栈帧都包含一个指向运行时常量池中该栈帧所属方法的引用,持有这个引用是为了支持方法调用过程中的动态连接。

返回地址(Return Adderss)

方法执行完(不论是正常执行还是发生了异常)后需要返回到方法被调用的位置,程序才能继续执行,方法但回事可能需要在栈帧中保存一些信息,用来帮助恢复上层方法的执行状态。

方法的退出过程实际上就等于把当前栈帧出栈。

  • 正常返回

    恢复上层方法的局部变量表和操作数栈。
    把返回值(如果有的话)压入调用者栈帧的操作数栈中。
    调整PC计数器的值以指向方法调用指令后面的一条指令。

  • 异常返回

    找到异常处理的栈帧

指向运行时常量池的引用

当前方法所属的类的运行时常量池的引用,引用其他的常量类或者使用String池中的字符串。

来源:

https://blog.csdn.net/justry_deng/article/details/86761833

https://www.bilibili.com/video/BV1uV411s7yu