Java虚拟机
运行时数据区
PC寄存器
- PC寄存器用来存储指向下一条指令的地址,即将要执行的指令代码,由执行引擎来读取。
- 在切换线程的时候,需要PC寄存器来知道接着从哪开始继续执行。
- 线程私有(保证了程序计数器在各个线程之间互不影响)
虚拟机栈
基本内容
- 每个线程对应一个虚拟机栈,栈帧对应一次次的方法调用
- 生命周期和线程一致
- 主管Java运行,保存方法的局部变量,对象的引用地址,参与方法调用和返回
栈帧的内容
- 局部变量表
- 操作数栈
- 动态链接(或指向运行时常量池的方法引用)
- 方法返回地址
- 一些附加信息
局部变量表
- 定义为数组,用于存储方法参数和定义在方法体内的局部变量
- 容量在编译器被确定下来
- 局部变量表中的变量只对当前方法有效
基本存储单元(Slot)
- 如果当前帧是由构造方法或实例方法创建,该对象的引用this会放在index为0的slot处。(静态方法没有this)
- 槽位可以重复利用
变量的分类
- 成员变量(静态变量,实例变量),会默认赋值
- 局部变量,使用前必须进行显示赋值
操作数栈
- 在方法执行过程中,根据字节码指令,往栈中写入数据或者提取数据,即push/pop。
- 如果被调用的方法有返回值,则返回值将会被压入当前栈帧的操作数栈中。
栈顶缓存技术
- 将栈顶的元素全部缓存在物理cpu的寄存器中,以此降低对内存的读/写次数。
动态链接
- 指向运行时常量池的方法引用
- 常量池的作用:提供一些符号和常量,便于指令的识别
方法的调用
- 静态链接:对应早期绑定
- 动态链接:对应晚期绑定
1. 非虚方法
在编译时确定了具体的调用版本,这个版本在运行时不可变
静态方法,私有方法,final方法,实例构造器,父类方法
子类对象多态性的使用前提:类的继承关系,方法的重写。
2. JVM中的方法调用指令
- invokestatic:调用静态方法
- invokespecial:调用
方法,私有及父类方法,解析阶段唯一确定方法版本 - invokevirtual:调用所有虚方法
- invokeinterface:调用接口方法
- invokedynamic:动态解析出需要调用的方法,然后执行
3. Java语言中方法重写的本质
- 找到操作数栈顶的第一个元素所执行的对象的实际类型,记作C
- 如果在则过程结束,否则找到常量中的相符的方法,进行访问权限校验,通过返回引用
- 否则,按照继承关系从下往上对C的各个父类进行第2步。
- 若找不到,则抛出java.lang.AbstractMethodError异常。
4.虚方法表
- 为了提高性能,JVM在解析阶段创建了一个虚方法表,表中存放各个方法的实际入口。
方法返回地址
- 存放调用该方法的pc寄存器的值。
- 调用者的pc寄存器的值作为返回地址,即调用该方法的指令的下一条指令的地址。
- 通过异常完成出口退出的不会给他的上层调用者产生任何的返回值。