4.虚拟机栈(线程私有)
一、虚拟机栈的概述(线程私有)
基于栈 的 设计的,跨平台
优点:跨平台、指令集小、编译器容易实现
缺点:性能下降、实现同样的功能 指令集多
1.1、堆管存储、、栈管运行
虚拟机栈的作用:主管java程序的运行,它保存方法的局部变量、部分结果,并参与方法的返回 和 调用
局部变量 vs 成员变量(或属性) :
基本数据类型的变量(8种) vs 引用类型的变量(地址)(类、数组、接口):
1.2、Java虚拟机栈是什么?
java虚拟机栈,早起叫 java栈
线程私有的 和 PC寄存器一样在
1.3、 虚拟机栈里存的是什么
栈帧: 一个栈帧 对应一个 java方法
1.4、 栈的优点(先进后出、后进先出)
存储速度很快、仅次于 PC 程序计数器
只有进栈和出栈 push 和pop
对于栈 是不存在 垃圾回收问题
不存在 gc 、存在 OOM
1.5、 面试:开发中遇到的异常有哪些?
栈溢出,递归常见 StackOverflowError异常
扩展的时候内存不够了 OutofMemoryError异常
设置虚拟机栈的大小 -Xss256k 后面数字是大小
二、栈的存储单位:栈帧
多个栈帧构成一个 栈,每个java方法对应一个栈帧,一一对应
栈帧是一块内存区、是一个数据的集合
复习:
OOP的基本单位:类、对象
类的基本结构:filed(属性、字段)、method(方法)
-------补充:栈顶就是当前栈帧(当前方法、当前类)
执行引擎的执行指令只针对 当前栈帧 的
java 方法有两种返回方式:
一种是 return
另一种是 抛出异常(没有处理的话)
两种方式都会导致 栈帧 被弹出
2.1 栈帧的内部结构
每个栈帧中存储着:
·**局部变量表
·**操作数栈(表达式栈)
·动态链接(或 指向运行时常量池的方法)
·方法返回地址(或方法正常退出、或异常抛出)
·一些附加信息
后面三个 也叫 帧数据区
2.2 局部变量表(Local veriables)(私有的)
是一个 数字数组
记录 :定义在方法体内的 局部变量 和参数 和 返回值
因为是线程 私有的 , 所以不会有 线程安全 问题 。
注意 : 非 静态方法 的话 会有 this 变量 在 index 为0 的位置
-----补充:slot double和long 占据两个 slot位 ,一个是 4位
栈帧当中的局部变量表的 槽 位 是可以被重复利用的
出了 作用域 就会被 销毁,后面 定义的变量 就会 占据 被销毁的变量的位置
如图 C占 的槽位(slot位) 就是B用剩下的
-----补充:变量的分类
变量的分类:
按照数据类型分:基本数据类型和引用数据类型
按照在类中声明的位置分:
成员变量和局部变量(在使用前必须要进行赋值)
成员变量还可以分为:类变量(static)和实例变量(在使用前都经历过默认初始化赋值)
类变量:linking给类变量 赋 默认值 ,初始化阶段 给类变量显示赋值(即静态代码块赋值)
实例变量:随着对象的会在堆 空间中 分配实例变量空间,并进行 默认赋值
-----补充:垃圾回收
局部变量表中的变量也是 重要的 垃圾回收 根节点,只要被局部变量表中直接或者间接引用的对象对不会被回收
2.3 操作数栈(Operand Stack)(私有的)
作用:在方法执行的过程当中,根据字节码指令,往 栈 中写入数据(push)和提取数据(pop)
主要作用:主要用于保存 计算过程中的中间结果,同时作为计算过程中变量 临时的存储空间
长度 在 编译期 就定义好了
-----补充:代码追踪
代码 1:
图解:第一步
··PC寄存器记录了 下一次要执行的 地址
··将 15 放入操作数栈(int) 中
··紧接着 PC 寄存器 要执行 地址为 2 的代码
··操作数栈 pop 指令, 存入 局部变量表中
图解:第二步
··PC寄存器 要执行索引为 3 的 指令
·· 将8 放入 操作数栈(int) 中
··紧接着 PC 寄存器 要执行 地址为 5 的代码
··操作数栈 pop 指令, 存入 局部变量表中
图解:第三步
··将 6 7 都 压 入操作数栈中 ,pop 执行add
图解:第四步
··执行 add 后 把结果 在 push 进 操作数栈中
··地址为9:pop操作数栈,将 结果 放入 局部变量中
------补充: 栈顶缓存技术(Top-Of-StackCashing)(私有的)
将栈顶元素全部缓存在 物理CPU的寄存器中,以此降低对内存的读/写速度,从而提升执行引擎的执行效率
2.4 动态链接(Dynamic Linking)
方法和变量引用 在 常量池中 , 栈帧中的 动态链接里 存的 就是 方法在常量池中的符号引用(地址)
作用就是:将符号引用转为真实引用
多个 线程 指向它 , 不存引用的话 ,每个 方法里 得给一份,所以,为了省内存,
存的是引用,指向 常量池 中的真实位置
------补充:方法的调用
静态链接:对应早期绑定
动态链接:对应晚期绑定:写代码(编译器)的时候确定不下来,例如 接口 =new ??
-----补充:虚方法和非虚方法
虚方法表 : (提高方法调用效率)
非虚方法:静态方法、私有方法、final方法、实例构造器、父类方法都是非虚方法(编译器就确定下来了,不存在多态的形式)、、其余的 是 虚方法
虚方法:和晚期绑定或者动态链接 对应的
-----补充:方法重写本质
2.5 方法返回地址(return address)
存放调用该方法的PC寄存器的值
相当于C语言,A调用B ,先把B函数的下一条地址压入A栈里(这里叫PC寄存器),然后B结束之后,好能知道 ,A函数 执行到哪里了