随笔分类
操作数栈 Operand Stack
也叫表达式栈 Expression Stack
栈可以用数组或者链表来实现
-
操作数栈,在方法的执行过程中,根据字节码指令,往栈中写入数据或读取数据,即入栈push和出栈pop
实际上这个过程是借助于执行引擎来完成的
- Java虚拟机中解释引擎是基于栈的执行引擎,其中栈指的便是操作数栈
-
操作数栈,主要用来存储计算的中间结果,也作为计算过程中变量临时的存储空间
-
操作数栈,就是JVM执行引擎的一个工作区,当一个方法刚开始执行(被调用)时,一个新的栈帧就会被创建出来,但此时这个方法的操作数栈是空的(但操作数栈是已经创建好了的)
-
在编译期,就定义好了每一个操作数栈用于存储数值的明确的栈深度,奥存在方法的Code属性中,为max_stack值.
-
数据占用栈深度和局部变量表一致,都是4个字节占用一个栈深度.
-
操作数栈并非采用索引的方式进行数据访问的,而是只能通过标准的入栈和出栈操作来完成一次数据访问(因为是栈嘛,虽然是用数组来实现的,但也不考虑用索引来访问数组了)
-
如果被调用的方法有返回值,其返回值也会被压入当前栈帧的操作数栈中,并且更新PC寄存器中下一条需要执行的指令
-
操作数栈中元素的类型必须要和字节码指令序列严格匹配,编译期在编译期间进行验证,同时在类加载过程中的类检验阶段的数据流分析阶段会进行再次验证
常见字节码指令分析
-
bipush:进栈操作 一个字节便能存储 PC占用两个指令长度(两个字节)
-
iconst : -1 ~ 5
-
sipush : short 两个字节来存储 -32768~32767
-
ldc : -2147483648~2147483647
-
-
istore:栈顶出栈操作(将操作数存储到局部变量表) 一个指令长度
-
iload:将一个局部变量的值复制加载到操作数栈(注意:此时局部变量表并不会少什么数据)
-
还有更多的指令,详情 https://www.cnblogs.com/wade-luffy/p/5929245.html
注意:方法中定义的变量会先压入操作数栈,然后存储到局部变量表
栈顶缓存技术
Top-of-Stack-Cashing
为什么要有这个技术?
JVM基于栈式架构设计的,所用的零地址指令更加紧凑,虽然实现简单,但完成一项操作的时候是需要更多的入栈和出栈指令,这也便就意味着需要更多的指令分配(Instruction Dispatch)以及内存的读写次数
为了解决这一问题,HotSpot JVM的设计们便提出了栈顶缓存技术
将栈顶元素全部缓存在物理CPU的寄存器中,以此来减少对内存的读写次数,提升执行引擎的执行效率
寄存器:指令更少,执行速度快