1. 运行时数据区的结构


每个JVM只对应一个Runtime实例

2. 线程

JVM虚拟机允许一个应用程序创建多个线程并行执行
在HotSpot JVM中,每个线程都和本地操作系统本地线程进行直接的映射

3.程序计数器

1).什么是程序计数器?

JVM中的PC寄存器是物理机器上的PC寄存器的一个模拟,存放下一条指令的位置

2).作用

存储下一条指令的地址

ps:线程私有的,无GC,无OOM,其中native方法在PC中为undefined

3)常见面试问题

  • 使用PC寄存器存储字节码指令地址有什么用?

因为CPU在不断的切换进程,用PC寄存,就能在切换回来的时候知道从哪里继续执行程序

  • 为什么PC寄存器是线程私有的

若不是私有的就会导致指令错乱,可能在CPU切换的时候运行别人的指令

4.虚拟机栈

1).什么是虚拟机栈?

主管Java程序的运行,它保存方法的局部变量,部分结果并参与方法的调用和返回

2).栈帧

虚拟机栈的基本单位,一个栈帧对于一个方法

ps: 虚拟机栈是线程私有的

  • 局部变量表
  • 操作数栈
  • 动态链接(指向运行时常量池的方法引用)
  • 方法返回地址(方法正常退出或异常退出的定义)

3).开发中遇到那些异常?

允许设置Java栈为固定值,若超过设置的最大容量就会发送StackOverflowError

若动态添加,在扩容内存大于能分配的内存的时候就会产生OutOfMemoryError

4)设置参数

-Xss 设置最大的栈大小

如-Xss 256k,默认大小约为linux 1024KB Mac 1024KB

5). 一些附加信息

①.局部变量表

定义一个数字数组,主要用于存储方法参数和定义在方法体内的局部变量,这些数据包括基本数据类型,对象引用以及returnaddress类型,在编译时就确定下来了,不存在数据安全问题
最基本的单位slot,32位以内的数据类型只占用一个slot,64位的占用2个slot
在构造方法或者实例方法中会将对象引用this存放在index为0的slot中,其余参数按照顺序排序。
slot可以重复利用,局部变量使用前必须显式赋值

<font color="red">局部变量表是重要的GCRoot,只要被局部变量表直接或者间接引用的变量不会被GC回收</font>

②.操作数栈

基本单位为栈深度,数组实现的栈
栈顶缓存技术,缓存在cpu的寄存器,降低内存的IO次数,提升执行引擎的效率

③.动态链接

在JVM中,将符号引用转换为调用方法的直接引用与方法绑定机制有关。

  • 动态链接
    只是在运行时可知,对应的方法绑定机制为:早期绑定和晚期绑定,绑定时一个字段、方法或者类的符号引用呗替换为直接引用的过程,这仅仅发生一次

    • 早期绑定(如调用父类构造器)
      目标方法在编译器可知,在运行期不变
    • 晚期绑定(如父类调用方法等)
      与之相反
  • 静态链接
    一个字节码文件被转载如虚拟机时,如果被调用目标方法在编译器可知

具备多态性就具有早期绑定和晚期绑定两种方法

5.虚方法和非虚方法

1).非虚方法:方法在编译期间就确定好了调用版本,这个版本运行时是不可变的
如:静态方法,私有方法,final方法,实例构造器,父类方法都是非虚方法
2).虚方法
其他方法均称为虚方法

6.方法重写的本质

step1.找到操作数栈栈顶的第一个元素所执行的对象实际类型记为C
step2.若类型C中找到常量中的描述符合并且简单名称都符合的方法,则进行访问权限校验,如果通过返回这个方法的直接引用,查找过程结束
step3.否则按照继承关系从下往上一次对各个父类进行搜索和验证过程
step4.始终未找到,则抛出java.lang.AbstarctMethodError

<font color='red'>每次调用都会进行这么一个过程,为了提升性能,JVM在类中方法区建立一个虚方法表,来用索引代替查找</font>

方法返回地址

1)作用

存放该方法PCC寄存器的值

2).方法结束的方式

①正常执行完成

②出现未处理的异常

无论哪种方式退出在方法退出后都会返回到该方法被调用的位置,方法正常退出,调用者的PC寄存器的值作为返回地址,即调用下一条指令的地址。而异常退出,返回地址是通过异常表确定的,栈帧中一般不会保存这部分信息

最后修改:2020 年 05 月 06 日
如果觉得我的文章对你有用,请随意赞赏