③. 操作数栈(operand stack)
①. 我们说Java虚拟机的解释引擎是基于栈的执行引擎,其中的栈指的就是操作数栈。
②. 每一个独立的栈帧中除了包含局部变量表以外,还包含了一个后进先出的操作数栈,也可以称之为表达式栈
③. 操作数栈,在方法执行过程中,根据字节码指令,往栈中写入数据或提取数据,即入栈或出栈
④. 每一个操作数栈都会拥有一个明确的栈深度用于存储数值,其所需的最大深度在编译期就定义好了,保存在方法的Code属性中,为max_stack的值
⑤. 栈中的任何一个元素都是可以任意的Java数据类型
32bit的类型占用一个栈单位深度
64bit的类型占用两个栈单位深度
⑥. 如果被调用的方法带有返回值的话,其返回值将会被压入当前栈帧的操作数栈中,并更新PC寄存器中下一条需要执行的字节码指令
⑦. 操作数栈,主要用于保存计算机过程的中间结果,同时作为计算过程中变量临时的存储空间 掌握
⑧. 操作数栈的具体说明[一]
这里的代码中操作数栈的长度最大是2,在iload_1、iload_2的时候
public void testAddOperation(){ byte i = 15; int j = 8; int k = i + j; }
解释:
- ⑧. 操作数栈的具体说明[二]
- 局部变量有多少个?
- 操作数栈的最大深度是多少?
public class OperandStackTest { public void testAddOperation(){ //byte、short、char、boolean:都以int型保存 byte i=15; short j=8; int k=i+j; long m=12L; int n=800; //存在宽化类型转换 m=m*n; } }
解释
⑨. 操作数栈的具体说明[三]
操作书栈的最大深度是2,这个2是在(new #2 、dup的时候)
public class OperandStackTest { public static void main(String[] args) { OperandStackTest test=new OperandStackTest(); int num=10; test.testAddOperation(); } public void testAddOperation(){ //byte、short、char、boolean:都以int型保存 byte i=15; short j=8; int k=i+j; long m=12L; int n=800; //存在宽化类型转换 m=m*n; }
0 new #2 <com/xiaozhi/jvm/OperandStackTest> 将new的对象放入操作数栈中 3 dup 复制一份出来,在操作数栈中,这时操作数栈的长度为2 下面用了dup出来的对象 4 invokespecial #3 <com/xiaozhi/jvm/OperandStackTest.<init>> 7 astore_1 将new出来的放入了局部变量表为1的位置,0的位置放的是arg 8 bipush 10 将10放入操作数栈 10 istore_2 将操作数栈中的10放入局部变量表为2的位置 11 aload_1 将巨变变量表1的位置放入操作数栈中 下面调用了方法,也就意味着操作数栈1的位置出栈了 12 invokevirtual #4 <com/xiaozhi/jvm/OperandStackTest.testAddOperation> 15 return
⑩. 何为栈顶缓存技术? 了解
前面提过,基于栈式架构的虚拟机所使用的零地址指令更加紧凑,但完成一项操作的时候必然需要使用更多的入栈和出栈指令,这同时也就意味着将需要更多的指令分派(instruction dispatch)次数和内存读/写次数。
由于操作数是存储在内存中的,因此频繁地执行内存读/写操作必然会影响执行速度。为了解决这个题,HotSpot JVM的设计者们提出了栈顶缓存(ToS,Top-of-Stack Cashing)技术,将栈顶元素全部缓存在物理CPU的寄存器中,以此降低对内存的读/写次数,提升执行引擎的执行效率