深入理解java虚拟机第八章笔记

第八章 虚拟机字节码执行引擎

一 运行时栈帧结构

栈帧适用于支持虚拟机进行方法调用和方法执行的数据结构,它是虚拟机运行时数据区中的虚拟机栈的战元素。栈帧存储了方法的局部变量表,操作数栈,动态连接和方法返回地址等信息。每一个方法从调用开始到执行完成的过程,都对应着一个栈帧在虚拟机栈里面从入栈到出栈的过程。

在活动线程中,只有位于栈顶的栈帧才是有效的,称为当前栈帧 Current Stack Frame,与这个栈帧相关联的方法称为当前方法。

1. 局部变量表:

是一组变量值存储空间,用于存放方法参数和方法内部定义的局部变量。在Java程序编译为Class文件时,就在方法的Code属性中确定了该方法所需要分配的局部变量表的最大容量。

局部变量表的容量以变量槽(slot)为最小单位。一个Slot可以存放一个32位以内的数据类型。对于64位数据类型,虚拟机会以高位对齐的方式为其分配两个连续的Slot空间。不过,由于局部变量表建立在线程的堆栈上,是线程私有的数据,无论读写两个连续的Slot是否为原子操作,都不会引起数据安全问题。

虚拟机通过索引定位的方式使用局部变量表。在方法执行时,虚拟机是使用局部变量表完成参数值到参数变量列表的传递过程。 如果执行的是实例方法(非static的方法),那局部变量表中第0位索引的Slot默认用于传递方法所属对象实例的引用,在方法中可以通过关键字“this”来访问这个隐含的参数,其余参数则按照参数顺序排列,占用从1开始的局部变量slot。

注意:类变量会经历两次赋值(有默认值)。而局部变量不会,所以局部变量如果定义但是不赋值是不能使用的。

2. 操作数栈:

Operand Stack也常称为操作栈,它是一个后入先出(Last In First Out, LIFO)栈。

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

例:整数加法的字节码指令iadd在运行时操作数栈中最接近栈顶的两个元素已经存入了两个int型的数据,当执行这个指令时,会将这两个int值出栈并相加,然后将相加的结果入栈。 

3. 动态连接:

每个栈帧都包含一个指向运行时常量池中该栈帧所属方法的引用,持有这个引用是为了支持方法调用过程中的动态连接。

4. 方法返回地址:

当一个方法开始执行后,只有两上方式可以退加该方法:执行引擎遇到任意一个方法返回的字节码指令,正常退出;在方法执行过程中出现异常,并且这个那异常没有在方法体内得到处理。


二 方法调用

方法调用阶段唯一的任务就是确定被调用方法的版本(即调用哪一个方法)。

解析:所有方法调用中的目标方法在Class里面都是一个常量池中的符号引用,会将其中的一部分符号引用转化为直接引用。主要包括静态方法和私有方法两大类。

分派:分派调用过程将为揭示多态特征的一些最基本的体现。

1、静态分派
Human man = new Man();

虚拟机在重载时是通过参数的静态类型(Human)而不是实际类型( Man )作为判定依剧的。 虚拟机会根据类型进行自动类型转换或装箱,可变长参数的重载优先级是最低的。

2、动态分派

与多态性的另一个重要体现 重写 override 有着很密切的关联。在判断是调用父类中的方法还是子类中的覆盖的方法时,根据对父类实例化的子类的不同,调用不同子类中覆写的方法。


猜你喜欢

转载自blog.csdn.net/llcream/article/details/80249258
今日推荐