我的JVM学习笔记:运行时数据区(3)操作数栈详解

感谢尚硅谷宋红康老师的JVM入门到精通课程,向每一个用心做免费教课程的老师致敬!
本套教程均为我学习课程之后的学习笔记,防止遗忘,并发送给大家分享,感谢大家查看~

1.上次内容

上次我们讲到,栈贞内部包含:局部变量表,操作数栈,动态链接,方法返回地址。
在上一篇文章中,我们着重介绍了局部变量表,有兴趣的可以去查看:我的JVM学习笔记:运行时数据区(2)局部变量表详解
本篇文章,让我们着重来学习一下栈帧存的包含的其他结构:操作数栈!

2.操作数栈详解(Operand Stack)

2.1栈的理解:

栈即可以使用数组实现也可以使用链表实现,先进后出(后进先出),只可以对尾部数据进行添加或删除,操作对应只有入栈和出栈,无法对中间数据进行直接操作!
在这里插入图片描述

2.2操作数栈:

每一个独立的栈帧中除了包含局部变量表以外,还包含一个后进先出的操作数栈,也可以称之为表达式栈(Expression Stack) 。

操作数栈,在方法执行过程中,根据字节码指令,往栈中写入数据或提取数据,即入栈(push) /出栈(pop)。

  • 某些字节码指令将值压入操作数栈,其佘的字节码指令将操作数取出栈。使用它们后再把结果压入栈。
  • 比如:执行复制、交换、求和等操作

举例:加法运算
在这里插入图片描述

示例代码:

public static void main(String[] args)
{
   int a = 8;
   int b = 15;
   int c = a + b;
}

在这里插入图片描述
执行流程分析:

JVM是基于栈的运行引擎,所有运算都只有入栈与出栈两种操作,并且在栈中才可进行运算。

  1. 当我们定义变量a,JVM会首先将操作数8压入栈,然后将操作数8出栈放入局部变量表index1的位置。
  2. 当我们定义变量b,JVM会首先将操作数15压入栈,然后将操作数15出栈放入局部变量表index2的位置。
  3. 因为JVM所有操作都在栈中进行,所以在运算a+b时,JVM会将ab的值分压入操作数栈,然后进行加法运算,得到结果23
  4. 运算完成后,操作数23自动成为栈顶,进行出栈操作,将23放入局部变变量表index3的位置(变量c),程序结束。

比喻理解:
如果将局部变量表比作货架,货架上放着8与15两个货物,而货架是无法直接对货物进行加工的,只能先将货物分别调运到加工区(操作数栈中),加工操作后再放入c货架。

总结:

  1. 操作数栈,主要用于保存计算过程的中间结果,同时作为计算过程中变量临时的存储空间

  2. 操作数栈就是JVM执行引擎的一个工作区,当一个方法刚开始执行的时候,一个新的栈帧也会随之被创建出来,这个方法的操作数栈是空的

  3. 每一个操作数栈都会拥有一个明确的栈深度用于存储数值,其所需的最大深度在编译期就定义好了,保存在方法的Code属性中,为max_ stack的值

    注意:

    • 操作数栈大小与局部变量表大小并无直接关系(确定于本方法中最多会有几个同时运算的操作数)!
    • 操作数栈的大小在编译时确定,并且无法改变!
      在这里插入图片描述
  4. 栈中的任何一个元素都是可以任意的Java数据类型

    • 32bit的类型占用一个栈单位深度.
    • 64bit的类型占用两个栈单位深度
  5. 操作数栈并非采用访问索引的方式来进行数据访问的,而是只能通过标准的入栈(push) 和出栈(pop)操作来完成一次数据访问。

  6. 如果被调用的方法带有返回值的话,其返回值将会被压入当前栈帧的操作数栈中,并更新PC寄存器中下一条需要执行的字节码指令。

    也就是说:如果此方法有返回值,正在方法结束之前,JVM会将返回值压入操作数栈,并且返回后可以直接将会返回值从当前栈取出并压入外部方法的操作数栈中。

    	public void test()
    		    {
    		        int a = getNum();
    		        int b = 0;
    		    }
    		
    		    public int getNum()
    		    {
    		        int b = 1;
    		        return b;
    		    }
    

    在这里插入图片描述

    getNum方法会将变量b的值压入操作数栈后返回

    在这里插入图片描述

    然后当执行到a的赋值操作时,直接从上一个方法的操作数栈中加载即可

栈顶缓存技术

基于栈式架构的虛拟机所使用的零地址指令更加紧凑,但完成一项操作的时候必然需要使用更多的入栈和出栈指令,这同时也就意味着将需要更多的指令分派( instruction dispatch) 次数和内存读/写次数。

由于操作数是存储在内存中的,因此频繁地执行内存读/写操作必然会影响执行速度。为了解决这个问题,HotSpot JVM的设计者们提出了栈顶缓存(ToS,Top-of-Stack Cashing)技术,将栈项元素全部缓存在物理CPU的寄存器中,以此降低对内存的读/写次数,提升执行引擎的执行效率。

也就是说:由于操作数栈读写非常频繁,所以jvm直降将栈顶元素全部缓存在cpu寄存器中,以便于增加访问速度!

总结:

操作数栈是JVM的核心概念之一,我们说Java是基于栈的执行引擎,这里的栈指的就是操作数栈,所以一定要对这方面的知识加以理解,感谢大家观看。

  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值