结构
寄存器
Pc寄存器作用: 每个线程存在一份,用来储存下一条指令的地址
唯一一个没有OOM的区域
虚拟机栈
a. 概述
保存一个个栈帧,对应一次次的JAVA方法调用,保存方法的局部变量,部分结果,参与方法的返回和调用
--Xss 1024k 设置虚拟机栈大小
b. 储存结构
储存结构是栈帧
方法和栈帧是一一对应的关系
栈帧是一个内存区块,是一个数据集
<!--栈帧的内部结构-->
1. 局部变量表
--定义为一个数字数组,主要是储存方法参数和定义在方法体内的局部变量,<基础类型|对象引用,teturnAddress类型>
--局部变量的大小是编译期就确定的
--线程私有,不存在数据安全问题
--方法嵌套调用的次数是由栈帧的大小决定
--局部变量表中的变量只有当前方法调用中生效
字节码指令:就是Line code 两行和对应的JAVAP命令所生成的数据对应关系
关于slot的理解
-- 局部变量表的最基础储存单元就是 slot [变量槽]
-- 32位及以下占用一个slot 包括引用类型,64位占用两个slot long类型和double类型
-- long 和 double按照起始索引开始计算
-- 排序是按照声明的顺序排序
-- 当前栈帧是由构造方法或者自己定义的非静态实例创建的,则默认会有this引用放在iNdex 0 处
-- slot的重复利用
局部变量和成员变量
--局部变量:在使用前,必须进行显示赋值,定义变量不赋值,直接打印,会编译错误
--成员变量:使用前都会经历默认初始化赋值
-- 局部变量表中的变量是重要的垃圾回收根节点,只要被局部变量表中直接或间接引用的对象都不会被回收
2. 操作数栈
-- 使用数组来实现 后进先出 push/pop
-- 操作数栈,主要用于保存计算过程的中间结果,同时作为计算过程中的变量临时存储空间
-- 操作数栈是属于JVM执行引擎的一个工作区,方法执行,栈帧创建,操作栈帧为空,但是数组存在长度
-- max_stack 在编译器就已经定义好,就是数组的长度
-- 32位及以下占用一个栈深度 包括引用类型,64位占用两个栈深度 long类型和double类型
-- 方法存在返回值,最终返回值是要被压入当前栈帧的操作数栈中
3. 动态链接 --帧数据区
-- 指向运行时常量池的方法引用
-- 栈顶缓存技术
零地址指令使指令更多,频繁出入栈,将栈顶元素全部缓存在CPU的寄存器中,提升执行引擎的速度
-- 方法的调用
# 虚方法
虚拟机指令: -- invokevirtual 调用所有虚方法 (除final)
-- invokeinterface 调用接口
# 非虚方法
方法在编译期就确定了调用版本且不可变,这样的方法就是非虚方法
例如: 静态方法,私有方法,final修饰的房啊,实例构造器,父类方法
虚拟机指令: -- invokestatic 调用静态方法,解析阶段确认唯一版本
-- invokespecial 调用<init>方法,私有方法及父类方法
# 虚拟机指令 invokedynamic
-- 动态类型语言和静态类型语言区别:对类型的检查是在编译期或者运行期进行,编译期:静态
-- 静态类型语言 java是静态语言
# 方法重写的本质
1. 找到操作数栈顶的第一个元素所执行的对象实际类型,记作C
2. 如果找到类型C的相符合方法,进行权限校验,不通过则怕抛出IllegalAccessError
3. 否则以此向父类查找,最终如果都没有,则抛出AbstractMethodError
# 虚方法表
1. 每个类都有一个,存放各个方法的实际入口
2. 解析环节创建
4. 方法返回地址
-- 保存PC寄存器的地址值信息,异常退出不保存这个信息
-- 正常退出和异常退出
5. 一些附加信息
c. 运行原理
不同线程中所包含的栈帧是不能互相引用的