虚拟机字节码执行引擎

运行时栈帧结构

  栈帧是用于支持虚拟机进行方法调用的和方法执行的数据结构,是虚拟机运行时数据区的虚拟机栈的栈元素,栈帧存储了方法的局部变量表,操作数栈,动态链接,方法返回地址等。
  每一个栈帧需要多大的内存在编译期间就确认了。

局部变量表

  在其,存放方法参数和方法内部定义的局部变量。

操作数栈

  也叫操作栈,是一个后入先出栈,当一个方法开始执行时,操作数栈是空的,在执行过程中,各种字节码指令会往操作数栈写入和提取内容。

动态连接

  每个栈帧都包含一个指向运行时常量池的引用,在Class文件中会有大量符号引用,一部分会在类加载时就直接转换为直接引用,一部分是在运行时转换为直接引用。

方法返回地址

  方法有2个方式退出,第一个是执行引擎遇到返回的字节码指令,正常退出。第二个就是遇到了异常,且没有被处理也会退出,这个是异常完成退出。无论哪种退出都要返回到方法被调用的位置,程序才能继续执行,正常退出时才会有这个值,异常退出时,一般不会保存这个值。

附加信息

  一些不在规范里面描述的信息,例如调试相关的信息,一般吧动态连接,方法返回地址。

方法调用

  在java中没有传统的连接步骤,存放在Class文件的是符号引用。

解析

  在类加载的解析阶段,会将一部分符号引用变成直接引用。这一部分是有要求的,就是方法调用在编译器就确认好了,不会发生变化的调用。
  在java中符合这个规范(编译器可知,运行期不可变的方法)是静态方法属于这个类,私有方法,外部不可访问,这2个类型的方法注定不会被重写或者继承产生其他版本。因此是在编译器就确认好了。

分派

静态分派

  A a=new B();其中B继承A,其中这个A是静态类型,这个B是实际类型。静态类型编译期间就可以知道确认,而实际类型必须在运行期间在可以确认。编译器不知道一个对象的实际类型是什么,在编译期间。
  在重载中

public void test(A a){...} ...1
public void test(B b){...} ...2

  如果传入A a=new B();把这个对象当参数穿进去,那么调用的是第一个方法,为何?因为这个虚拟机在重载时根据的是参数的静态类型进行判断的,而静态类型却是在编译期间就可以知道的,因此在编译期间就将符号引用确认了。凡是通过静态参数确认的都是静态分配。

动态分配

  动态分配和java中的重写密切相关。动态分配哈java字节码的一些指令相关度很高,他就是更具对象的实际类型类指定的,和对象实际类型相关。这是和java字节码的解析相关的,字节码就是这么解析的。

猜你喜欢

转载自www.cnblogs.com/donghang/p/9233690.html