Skip to content

栈的生命周期和线程是相同的,线程创建时创建栈,线程销毁时栈随之销毁。

虚拟机栈描述的是Java方法执行的内存模型:栈帧(Stack Frame)是用于支持Java虛拟机进行方法调用和执行的数据结构,它是虚拟机栈中的栈元素。

每个方法在执行的同时都会创建一个栈帧用于存储局部变量表、操作数栈、动态链接、方法出口等信息。

image-20230724220233986

局部变量表

作用:局部变量表用于存放变量,也就是方法参数、方法体内的变量,生命周期和栈相同。

局部变量表存储了哪些类型?

局部变量表的数据类型是slot (变量槽)、而且只有一 个数据类型,一个slot槽是32bit;

在原始数据类型中,分为8种基本类型(byte short int long float double char boolean)和returnAddress类型,小于32bit装一个slot, 大于32bit装2个槽位,例如long和double装两个槽位。

局部变量表中的对象引用

上文说明了基本类型是如何引用的,那么对象类型呢?

对象类型变量的值大小是不规定的,因此slot槽不会直接存放值,对象类型只会占用一个槽。具体的如图所示,这个referece对象引用,需要涉及3个区域:栈、堆、方法区

  • 栈帧:本地变量表,存放了referece对象引用;
  • 堆:存放了对象实例的数据,例如对象中的变量name=abc;
  • 方法区:存放对象的类型数据(对象类型、父类、实现接口、方法、常量等等)的地址信息。

image-20230724223015166

操作数栈的压栈与出栈

JVM操作数栈是一种堆栈数据结构,用于存储计算过程中的操作数和中间结果。在执行Java字节码指令时,操作数栈会被用来存放操作数,以及进行各种操作数的入栈和出栈操作。

压栈(Push)是指将操作数或结果推入操作数栈顶,常见的压栈操作包括:

  1. 常量入栈:将常量值(如int、float、String等)入栈。
  2. 方法参数入栈:将方法的参数入栈。
  3. 运算结果入栈:将两个操作数进行计算后的结果入栈。

出栈(Pop)是指将操作数栈顶的元素取出,并从操作数栈中移除,常见的出栈操作包括:

  1. 赋值操作:将栈顶元素赋值给一个变量。
  2. 运算操作:将栈顶的操作数取出进行运算。
  3. 方法返回值:将方法的返回值从栈顶取出。

在JVM中,操作数栈是基于栈帧(Stack Frame)实现的。每个方法在JVM中都会对应一个栈帧,用于保存方法的局变量表、操作数栈、动态链接、方法返回地址等信息。栈帧中的操作数栈用于存储方法执行过程中的操作数和中间结果。

总结起来,JVM操作数栈的压栈操作就是将操作数或结果推入栈顶,出栈操作是将栈顶元素取出并从栈中移除。这些操作在执行Java字节码指令的过程中会频繁地进行,用于存储和处理操作数。

案例如下:左侧是字节码,右侧是源代码,数栈的压栈与出栈操作如图所示。

操作数栈