虚拟机栈虚拟机栈

虚拟机栈

为什么要用栈而不用寄存器?

答:

  • java是跨平台语言,如果用寄存器结构,则不同cpu架构不同,通用型下降。
  • 跨平台使用,指令集比较小,编译速度快(但是也导致实现相同功能需要的指令更多,性能较低。)

堆和栈

栈是每个线程都会创建一个,是线程私有的,每个栈的生命周期同步于线程的生命周期。内部保存的是一个个栈针,每个栈针对应这一个方法,栈顶方法称为当前方法。还会保存一部分变量(局部变量(八种基本变量),以及一些引用(应用类型数据的引用))
堆空间一般是比较大的
与PC寄存器相比,也不需要使用GC回收,但是会出现OOM(栈溢出异常)。

java栈有哪些异常?

在这里插入图片描述

栈空间大小配置

IDEA 当中配置:
-Xss256K 也可以-Xss256M 配置栈内存空间大小
在这里插入图片描述

栈储存空间

栈存储的是栈针,每个栈针就是一个内存空间,是一个数据集合,维护着变量和方法,栈针和方法是一对一关系。

java栈运行原理

  • 不同线程之间栈相互隔离
  • 当前方法栈针调用其他方法,如果有返回值,方法返回的之时,当前栈针会把当前结果传给前一个栈针,然后虚拟机放弃当前栈针。
  • 无论是方法结束还是抛出异常,栈针都会被弹出。

在这里插入图片描述

栈针内部分析

在这里插入图片描述

局部变量表

又称为局部变量数组或者本地变量表

定义了一个数字数组,主要用于存储方法参数以及定义在方法体内的变量,包括基本数据类型、对象引用、返回值类型。
由于是栈针私有数据不存在安全问题,只在当前方法有效。
局部变量表的大小在编译期就会根据所需大小确定了。运行时无法改变。

局部变量表当中的每一个储存单元称为slot(槽),32位之内的数据占用一个槽,64占用两个槽(long double 等,以第一个槽为该索引)。在实例方法和构造方法当中局部变量表第一位是this,表示当前对象。因此只能在实例方法和构造方法当中使用this,静态方法的局部变量表当中没有this变量。
在这里插入图片描述
注意:

  public void test1(){
        int i =1;
        StringBuffer stringBuffer = new StringBuffer();
        {
            int j = i + 1;
        }
        int k = i + 1;
    }

局部变量池总共有四个变量,this i stringBuffer的索引 k
由于有实例代码快,其中变量 j 的作用于就在代码快当中,出了代码快就不能用,因此会先创建一个变量,然后一个k 将 j 替代,二者共同一个槽。
在这里插入图片描述

操作数栈

每一个栈针当中除了变量表还有操作数栈,也称为表达式栈,就是用来在计算过程中保存临时变量的,计算完成以后会把数据保存在局部变量表当中。

同局部变量表一样,32位使用一位,64占用两个空位。
在这里插入图片描述
举例:

    public void test1(){
        int i = 8;
        int j = 7;
        int s = i + j;
    }

以上述代码为例:

在这里插入图片描述
首先就是PC寄存器当中存有操作指令,局部变量表确定好大小但是为空,操作栈为空

  1. 执行指令0 在操作数栈当中保存15
  2. 执行2, 操作数栈弹栈,局部变量表保存变量。
  3. 执行3…
  4. 执行10, 方法结束,栈针结束。

动态链接

栈针结构图

每个栈针内部都保存着一个指向运行时常量池当中的该栈针所属方法的引用,就是动态链接
在这里插入图片描述

所以动态链接干嘛的?
调用其他方法或者引用的时候,动态链接在方法区运行时常量池当中找到对应的变量和方法,而不需要自己保存该方法或者变量。
为什么这么做?
为了重复利用该方法,每个栈针保存的是引用,都指向方法区常量池当中的方法或实例变量,可以减少内存使用。如下图:

栈帧就是方法,通过动态链接指向真正的方法,那怎么把符号引用转换为调用方法的呢?什么时候绑定?

通过静态绑定(早期绑定)或者 动态绑定(晚期绑定),如果调用的方法在编译期已经知道,且后期不在改变(比如调用类的直接方法),就是静态绑定,如果是通过多态,父类型引用调用子类方法,就会后期绑定。

虚方法和非虚方法?

除了静态方法、父类方法、final修饰方法、私有方法和实例构造方法是非虚方法,其他都是虚方法。非虚方法就是早起绑定,虚方法是后期绑定,因为在编译期无法确定调用的具体是哪个方法,所以称为虚方法。

方法调用指令:
方法调用指令

方法返回地址(栈帧空间的一部分)

方法返回地址是存储的是PC寄存器当中下一条方法的返回值,返回给执行引擎,让执行引擎可以继续执行。PC寄存器中存数的是什么,下一条将要执行的指令值,方法返回值会存在操作数栈当中,使得执行引擎可以操作。

程序结束有两种可能:第一:正常执行结束,第二:产生异常。如果正常执行结束,执行引擎会继续把方法返回值返回给上一层方法,如果出现异常,就会通过异常信息表抛出异常,此时不会有返回值地址

面试题

好简单!!!
在这里插入图片描述

  1. StackOverFlowError
  2. 不能保证
  3. 不一定
  4. 不会,虚拟机栈只有pop和push,不需要垃圾回收
  5. 不一定,如果是实力方法,方法内部定义的变量是线程安全,如果是通过方法中参数传递发过来,可能会线程不安全,对于静态方法,如果返回给其他方法调用,就有可能会线程不安全。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值