一、概念
Java虚拟机栈(Java Virtual Machine Stack)
虚拟机栈描述的是Java方法执行的线程内存模型:每个方法被执行的时候,Java虚拟机都会同步创建一个栈帧(Stack Frame)用于存储局部变量表、操作数栈、动态连接、方法出口等信息。每一个方法被调用直至执行完毕的过程,就对应着一个栈帧在虚拟机栈中从入栈到出栈的过程。它是线程私有的,它的生命周期与线程相同。(摘自深入理解Java虚拟机-第三版)
- 栈帧:虚拟机栈中的最小执行单元(每一个栈帧对应一个java方法)
- 局部变量表:一组变量值的存储空间,用于存放方法参数及内部定义的局部变量。
- 变量槽:局部变量表以最小单位-变量槽来表示
- 操作数栈:也常被称为操作栈,它是一个后入先出(Last InFirst Out,LIFO)栈
Java虚拟机栈执行示意图
二、概念剖析
变量槽
1》 一个变量槽可以存放一个32位以内的数据类型,Java中占用不超过32位存储空间的数据类型有boolean、byte、char、short、int、float、reference和returnAddress这8种类型。
注:reference类型表示对一个对象实例的引用---简单理解为:通过引用可找到真实对象地址或类型信息等(本章不扩展)
2》对于64位的数据类型,Java虚拟机会以高位对齐的方式为其分配两个连续的变量槽空间。Java语言中明确的64位的数据类型只有long和double两种
访问:Java虚拟机通过索引定位的方式使用局部变量表,索引值的范围是从0开始至局部变量表最大的变量槽数量。如果访问的是32位数据类型的变量,索引N就代表了使用第N个变量槽,如果访问的是64位数据类型的变量,则说明会同时使用第N和N+1两个变量槽。
【简汇: 索引值从0开始,32位数--->第N个变量槽 64位数--->第(N 和N+1)变量槽】
三、操作数栈 + 局部变量表执行示意图分析
目的:计算c = a + b的值
一、代码示例:
public int add() {
int a = 100;
int b = 200;
int c = a + b;
return c;
}
二、字节码示例及含义
字节码 | 含义 | 示例 | 释义 |
---|---|---|---|
bipush | Push byte | bipush 100 | 字节立即被符号扩展为int值,该值被压入操作数栈中 |
istore_n | Store | istore_1 | 索引1是一个无符号字节,必须是当前栈帧的局部变量数组的索引,操作数栈顶值必须是int类型。 它从操作数栈中弹出,并且索引值1的局部变量表的值设置为对应value |
sipush | Push | sipush 200 | 无符号立即数byte1和byte2的值组合成一个中间short,其中short的值为(byte1 << 8)| 字节2。 然后将中间值符号扩展为int值。 该值被压入操作数堆栈。 |
iload_n | Load | iload_1或iload_2 | 索引处(1|2)的局部变量必须包含一个int。 索引处的局部变量的值被压入操作数堆栈。 |
iadd | Add
..., value1, value2 → ..., result ) | iadd | value1和value2都必须为int类型。 从操作数堆栈中弹出值。 int结果为value1 + value2。 结果被压入操作数堆栈。 (结果是具有足够宽的二进制补码格式的真实数学结果的32个低位,表示为int类型的值。 如果发生溢出,则结果的符号可能与两个值的数学和的符号不同。 尽管可能会发生溢出,但是执行iadd指令绝不会引发运行时异常) |
ireturn | Return | ireturn | 从当前帧的操作数堆栈中弹出值,并将其压入调用者的帧的操作数堆栈。 当前方法的操作数堆栈上的任何其他值都将被丢弃 |
更多参考【字节码指令官方地址】
三、代码指令执行示意图
注:以下按照字节码执行指令顺序分析,请参考下图即可
以上则是java虚拟机栈之操作数栈+局部变量表执行示意图,作为个人学习及分享记录,如有误请指正,谢谢。