虚拟机栈
出现背景
由于跨平台的设计,Java指令都是根据栈来设计,不同CPU架构不同,所以不能设计为基于寄存器的。
- 优点:指令集小,编译器容易实现
- 缺点:性能下降,实现同样操作需要更多指令。
为什么Java开发人员一提到Java内存结构,就会将内存区理解为堆和栈?
栈是运行的单位。堆是存储的单位
Java虚拟机栈是什么?
Java Virtual Machine Stack,每个线程在创建时都会创建一个虚拟机栈,其内部保存一个个的栈针,对应着一次一次的方法调用。
生命周期
和线程生命周期一起。
作用
- 管理程序运行,保存方法的局部变量(基本数据类型和对应引用地址)、部分结果、并参与方法的调用和返回。
栈的特点
- 快速分配存储的方式,速度仅次于程序计数器。
- 每个方法执行都伴随进栈和出栈。
- 不存在垃圾回收问题。
设置栈内存大小
我们知道,在递归执行时,如果没有正确指明返回条件,会抛出StackOverflowError异常。
另外一种情况就是分配的大小超出了栈的空间。
可以通过-Xss来设置线程最大的栈空间。这个值决定了函数调用的最大可达深度。
栈的存储单位
栈中存储什么?
每个线程都有自己的栈,栈中的数据都是以**栈帧(Stack Frame)**格式存在。
-
栈帧是一块内存,一个数据集。维系方法执行过程中的各种数据信息。
-
JVM对栈的操作只有压栈和出栈,遵循先进后出。
-
线程的一个时间点上,只有一个活动栈帧,这个栈针叫做当前栈帧,对应的方法叫当前方法,对应的类叫当前类。
栈运行图解
解释
- 不同线程中包含的栈帧不允许相互引用。
- 每个栈帧对应的方法结束返回之际,JVM会丢弃该栈帧,使前一个栈针重新成为当前栈帧。
- 方法有两种返回形式:一是return指令正常返回;二是抛出异常。
栈的内部结构
局部变量表
- 定义数字数组,存储方法参数和定义在方法体内的局部变量。包括基本数据类型、对象引用,以及returnAddress类型。
- 局部变量表建立在线程的栈上,所以不存在数据安全问题。
- 其容量大小在编译期确定下来。
局部变量表中Slot的理解
- slot是其基本存储单位。
- 32位内的类型栈一个slot(如int,不是int的会转换成int),64位类型占两个slot(如double和long)
我们知道静态方法不能使用this,为什么?
因为this这个变量不存在于当前这个静态方法的局部变量表。换句话说,静态方法局部变量表中没有this,非静态方法中存在this。
操作数栈
每个栈针除了局部变量表外,还包含一个先进后出的操作数栈。也叫表达式栈。
- 操作数栈,在方法执行中,根据字节码指令,往栈中写入数据或提取数据,即入栈/出栈。
- 如果调用的方法带有返回值,其返回值将会被压入当前栈针操作数栈中,随即更新PC寄存器中下一条需要执行的字节码指令。
- 用于保存计算过程中的中间结果,同时作为计算过程中的临时的存储空间。