一、概述

  执行引擎是虚拟机中最核心的部分之一, 虚拟机自己实现引擎,自己定义指令集和执行引擎的结构体系。

二、栈帧

  栈帧包含(1)局部变量表、(2)操作数栈、(3)动态链接、(4)方法返回地址、(5)额外的附加信息

  栈顶的栈帧为当前栈帧,是唯一有效的。

  2.1 局部变量表

  用于存放方法参数和方法内部定义的局部变量。单位为槽(Slot),每个槽可以存放一个变量(Boolean,byte,char,short,int,float,reference,returnAddress),lonng,double需要两个槽。

  2.2 操作数栈

  Java虚拟机引擎称为“基于栈的执行引擎”,栈就是操作数栈。

  2.3 动态链接

  每个栈帧都有一个指向运行时常量池的所属方法引用,目的是:支持动态链接。

  静态链接:Class文件中有大量的符号引用,字节码中方法调用指令,以常量池中指向方法的符号引用为参数在类加载阶段或者第一次使用时候会转化为直接引用。

  动态链接,在运行期间化为直接引用。

  2.4 方法返回地址

  两种方法退出:(1)遇到返回关键字。(2)遇到异常

  实际操作:当前栈帧出栈,恢复上层方法的局部变量表和操作数栈,返回值压栈(操作数栈)

  2.5 附加信息

  允许具体的虚拟机实现增加一些描述信息。

  

三、方法调用

  方法调用:确定要调用的版本(即:调用哪个方法)

  3.1 解析

  所有方法在Class文件中都是一个字符串的常量引用,在类加载期间会将其转换为直接引用。

  解析:方法在真正运行之前必须有一个确定版本,并在运行期是不可变的。

  3.2 分派
  3.2.1静态分派

  依赖静态类型来进行方法执行版本的分派动作。

  发生时期:编译阶段

  调用指令:invokestatic

  应用:方法重载

public class StaticDispatch {
static abstract class Human { } static class Man extends Human { } static class Woman extends Human { } public void sayhello(Human guy) {
System.out.println("Human guy"); } public void sayhello(Man guy) {
System.out.println("Man guy"); } public void sayhello(Woman guy) {
System.out.println("Woman guy");
} public static void main(String[] args) {
Human man = new Man();
Human woman = new Woman();
StaticDispatch staticDispatch = new StaticDispatch();
staticDispatch.sayhello(man);// Human guy
staticDispatch.sayhello(woman);// Human guy
} }

  输出结果:

  Human guy

  Human guy

  原因:

  下一行代码:

Human man = new Man();

  其中Human为静态类型, Man为 实际类型 

  两者的区别是:静态类型编译期间可知, 实际类型运行期可知。

  重载是通过编译期间的静态类型确定调用哪个函数, 所以Javac会根据静态类型 Human来确定调用的函数为 sayhello(Human guy)

  

  3.2.2 动态分配

  运行期根据实际类型确定方法执行版本的过程为动态分配。

  调用指令:invokevirtual

  应用:方法重写

  

public class DynamicDisptch {

    static abstract class Human {
abstract void sayhello();
} static class Man extends Human { @Override
void sayhello() {
System.out.println("man");
} } static class Woman extends Human { @Override
void sayhello() {
System.out.println("woman");
} } public static void main(String[] args) {
Human man = new Man();
Human woman = new Woman();
man.sayhello();
woman.sayhello();
man = new Woman();
man.sayhello();
} }

  运行结果:

man say hello
woman say hello
woman say hello

  

  动态分配运行时解析过程:

  1. 找到操作数栈顶的第一个元素所执行的对象的实际类型,记作 C。
  2. 如果在类型 C 中找到与常量中的描述符合简单名称都相符的方法,则进行访问权限校验,如果通过则返回这个方法的直接引用,查找过程结束;如果不通过,则返回 java.lang.IllegalAccessError 异常。
  3. 否则,按照继承关系从下往上一次对 C 的各个父类进行第 2 步的搜索和验证过程。
  4. 如果始终没有找到合适的方法,则抛出 java.lang.AbstractMethodError 异常。

  invokevirtual 指令在运行期确定接受者的实际类型,所以会将同一个方法解析到不同的函数上。这就是Java重写的本质。

  

  3.3 单分派与多分派

  方法接收者与方法参数统称为方法的宗量,根据分派基于多少种宗量,可以分为单分派和多分派两种,

  单分派:根据一个宗量对目标的方法选中

  多分派:根据多个宗量进行目标方法选中

  

/**
* 单分派、多分派演示
*
*/
public class Dispatch { static class QQ {} static class _360 {} public static class Father {
public void hardChoice(QQ arg) {
System.out.println("father choose qq");
} public void harChoice(_360 arg) {
System.out.println("father choose 360");
}
} public static class Son extends Father {
public void hardChoice(QQ arg) {
System.out.println("son choose qq");
} public void harChoice(_360 arg) {
System.out.println("son choose 360");
}
} public static void main(String[] args) {
Father father = new Father();
Father son = new Son();
father.harChoice(new _360());
son.hardChoice(new QQ());
}
}

  运行结果:

  

father choose 360
son choose qq

  静态分配:在编译阶段,也就是静态分配过程中,选择目标的依据有两点:(1)静态类型是 Father 还是 Son(2) 方法的参数是 QQ还是 360。 所以静态分配为多分派。

  动态分配:在运行阶段,也就是动态分配过程中,由于静态分配过程中已经知道函数必须是 hardChoice(QQ arg) ,其中参数的类型编译器不会关心, 只会在意方法的接受者到底是Father 还是 Son 所以动态分配为 单分派。

  3.4 虚拟机动态分派的实现

  动态分配需要查找合适的方法,为了提高性能, 一般的处理方法是:用稳定的手段,为类在方法区建立一个虚的方法表。使用索引表来代替查找。

  虚方法表中存储了各个方法的实际入口,如果在子类中没有重写该方法,那么子类的虚方法表中的地址和父类的一样, 如果重写了,则指向重写之后的方法入口地址。

  初始化时间:虚拟方法表一般在类加载链接期间进行初始化,准备好初值之后虚拟机会将类方法初始化完毕。

  

【Java】JVM(六)虚拟机字节码执行引擎的更多相关文章

  1. 【JVM】虚拟机字节码执行引擎

    概念模型上,典型的帧栈结构如下(栈是线程私有的,也就是每个线程都会有自己的栈).                     典型的帧栈结构 局部变量表 存放方法参数和方法内部定义的局部变量.在编译阶段, ...

  2. 【java虚拟机系列】从java虚拟机字节码执行引擎的执行过程来彻底理解java的多态性

    我们知道面向对象语言的三大特点之一就是多态性,而java作为一种面向对象的语言,自然也满足多态性,我们也知道java中的多态包括重载与重写,我们也知道在C++中动态多态是通过虚函数来实现的,而虚函数是 ...

  3. java虚拟机字节码执行引擎

    定义 java虚拟机字节码执行引擎是jvm最核心的组成部分之一,它做的事情很简单:输入的是字节码文件,处理过程是字节码解析的等效过程,输出的是执行结果.在不同的虚拟机实现里,执行引擎在执行java代码 ...

  4. 深入理解JVM虚拟机5:虚拟机字节码执行引擎

    虚拟机字节码执行引擎   转自https://juejin.im/post/5abc97ff518825556a727e66 所谓的「虚拟机字节码执行引擎」其实就是 JVM 根据 Class 文件中给 ...

  5. 《深入理解Java虚拟机》-----第8章 虚拟机字节码执行引擎——Java高级开发必须懂的

    概述 执行引擎是Java虚拟机最核心的组成部分之一.“虚拟机”是一个相对于“物理机”的概念 ,这两种机器都有代码执行能力,其区别是物理机的执行引擎是直接建立在处理器.硬件.指令集和操作系统层面上的,而 ...

  6. Java虚拟机--虚拟机字节码执行引擎

    Java虚拟机--虚拟机字节码执行引擎 所有的Java虚拟机的执行引擎都是一致的:输入的是字节码文件,处理过程是字节码解析的等效过程,输出的是执行结果. 运行时栈帧结构 用于支持虚拟机进行方法调用和方 ...

  7. Java虚拟机-字节码执行引擎

    概述 Java虚拟机规范中制定了虚拟机字节码执行引擎的概念模型,成为各种虚拟机执行引擎的统一外观(Facade).不同的虚拟机引擎会包含两种执行模式,解释执行和编译执行. 运行时帧栈结构 栈帧(Sta ...

  8. JAVA虚拟机:虚拟机字节码执行引擎

    “虚拟机”是一个相对“物理机”的概念,这两种机器都有代码执行能力. 物理机的执行引擎是直接建立在处理器.硬件.指令集和操作系统层面上的. 虚拟机的执行引擎由自己实现,自行制定指令集与执行引擎的结构体系 ...

  9. JVM基础结构与字节码执行引擎

    JVM基础结构 JVM内部结构如下:栈.堆. 栈 JVM中的栈主要是指线程里面的栈,里面有方法栈.native方法栈.PC寄存器等等:每个方法栈是由栈帧组成的:每个栈帧是由局部变量表.操作数栈等组成. ...

  10. 深入了解java虚拟机(JVM) 第十三章 虚拟机字节码执行引擎

    一.概述 执行引擎是java虚拟机最核心的组成部件之一.虚拟机的执行引擎由自己实现,所以可以自行定制指令集与执行引擎的结构体系,并且能够执行那些不被硬件直接支持的指令集格式.所有的Java虚拟机的执行 ...

随机推荐

  1. php设计模式之职责链模式

    <?php /** * @desc php设计模式之职责链模式(责任链模式) 定义:顾名思义,责任链模式为请求创建了一个接收者对象的链.这种模式给予请求的类型,对请求的发送者和接收者进行解耦.这 ...

  2. php文章付费阅读系统球料付费阅读系统

    服务项目 新手技术咨询 企业技术咨询 定制开发 服务说明 QQ有问必答 QQ.微信.电话 微信开发.php开发,网站开发,系统定制,小程序开发 价格说明 200元/月 1000/月 商议       ...

  3. 【Spring实战-3】Spring整合Hibernate、Struts

    作者:ssslinppp      1. 摘要 版本: Spring4.0.4:Hibernate4.3.5:struts2.3.16: 主要介绍了如下内容: 项目结构的规划: Spring下整合Hi ...

  4. 自绘图片下拉项 combobox listbox

    using System;using System.Collections.Generic;using System.ComponentModel;using System.Data;using Sy ...

  5. 关于ESXI5.0版本+ Broadcom BCM5720的BUG

    主要发生在网卡 Broadcom Corporation NetXtreme BCM5720 Gigabit Ethernet 和ESX 5.0之前的版本. 虚拟机的网络突然不通,必须删除网卡重新创建 ...

  6. 模型融合策略voting、averaging、stacking

    原文:https://zhuanlan.zhihu.com/p/25836678 1.voting 对于分类问题,采用多个基础模型,采用投票策略选择投票最多的为最终的分类. 2.averaging 对 ...

  7. unity3d中gameObject捕获鼠标点击

    gameObject需加上Colider 一.在update中(推荐) void Update () { //左键 )) disFlag = true; //右键 )) disFlag = true; ...

  8. Apache Kudu as a More Flexible And Reliable Kafka-style Queue

    Howdy friends! In this blog post, I show how Kudu, a new random-access datastore, can be made to fun ...

  9. xiao look 知识贴

    从事中医临床近二十年了,多少总是积累了点经验,本来准备将来老了经验更丰富的时候传给子女的,可惜儿子根本不打算学医.在这个论坛里也混了不短了,感觉这里的风气很纯正,也有不少立志于中医的人士.为此,我决定 ...

  10. Python中的LEGB规则

    目标 命名空间和作用域——Python从哪里查找变量名? 我们能否同时定义或使用多个对象的变量名? Python查找变量名时是按照什么顺序搜索不同的命名空间? 命名空间与作用域的介绍 命名空间 大约来 ...