JVM(五)——JVM如何执行代码之执行引擎

       前边,我们学习总结了JVM的内存区域分布内存回收机制、及装载文件.class的文件组成结构,还有.class文件的装载过程。好,接下来,我们来看看装载好.class文件,jvm如何进行执行其代码。

      我们都知道,我们写的代码,为了实现业务主要是执行其中的方法。都说项目=逻辑+数据,逻辑,即我们写的业务代码,数据及数据库、各种缓存、client本地存储等存储的数据。好,那么我们代码的执行,重点也是方法的执行。

      一,栈组成栈帧:

      最开始我们学习总结JVM内存区域分布中,有一块叫栈,他是用来执行存储我们程序执行的(栈数据结构后进先出——LIFO),其特点完全符合我们方法执行顺序。好,这里我们来学习一下栈的组成元素——栈帧。首先来看下栈帧的组成结构图:

      下边,我们来看看这几个组成元素:

栈帧组成结构
元素名称 描述
1-局部变量表(Local Variable Table)

1,为一组变量值存储空间,用于存放方法参数和方法内定义的局部变量。

2,最小单位变量槽(Variable Slot),可以存放boolean、byte、char、short、int、float、reference、returnAddress8中数据类型。

2-操作数栈(Operand Stack) 也为操作栈,为后入先出LIFO结构,就是方法执行过程中,会有各种字节码指令往操作栈中写入和提取内容,即入栈、出栈操作。举个最简单例子:a=b+c*d,大家可以想象一下过程。
3-动态连接(Dynamic Linking) 每个栈帧都包含一个执行运行时常量池中该栈帧所属方法的引用,支持方法调用过程的动态链接。
4-方法返回地址

1,正常返回,遇到方法返回的字节码指令,返回值传递给上层的方法调用者。也就是程序的正常执行返回。

2,异常返回,程序执行遇到异常,返回的。

5-附加信息 其它的一些信息,例如调试相关的信息……

      栈帧的功能,是我们程序执行,方法调用的基础。我们再来看看,方法是如何进行调用的。

       二,方法如何调用:

       其实方法调用的难就难在面向对象的继承、封装和多态上,有反射生成新的类,新的方法,有重写、重载使同一个方法名有了不同的执行流程。

        方法调用其实就是确定调用方法的版本(即调用那个方法)。有些在解析阶段就能确定,有的只能在运行阶段动态判断。

        解析:解析阶段将其中的一部分符号引用转化为直接引用的前提是能够确定的调用版本。主要包括:静态方法和私有方法。看下字节码调用指令,其中只有invokestatic和invokespecial表示的会在解析中确定。

invokevirtual

 
指令用于调用对象的实例方法,根据对象的实际类型进行分派(虚方法分派),这也是Java语言中最常见的方法分派方式。
invokeinterface 指令用于调用接口方法,它会在运行时搜索一个实现了这个接口方法的对象,找出适合的方法进行调用。
invokespecial 指令用于调用一些需要特殊处理的实例方法,包括实例初始化(<init>)方法、私有方法和父类方法。
invokestatic 调用静态方法(static方法)。
invokedynamic 指令用于在运行时动态解析出调用点限定符所引用的方法,并执行该方法,前面4条调用指令的分派逻辑都固化在Java虚拟机内部,而invokedynamic指令的分派逻辑是由用户所设定的引导方法决定的。

        分派:1,静态分派:依据静态类型(List list = new ArrayList()List为静态类型,ArrayList为实际类型)来定位执行版本的分派动作为静态分派。典型:重载;

                   2,动态分派:运行期根据实际类型确定方法执行版本的过程。典型:重写;

        方法调用如何确定,方法如何执行,业务代码怎么执行,本篇进行了简单的讲述。栈帧、方法调用。好,继续……

猜你喜欢

转载自blog.csdn.net/liujiahan629629/article/details/86559388
今日推荐