虚拟机和物理机的区别。两种都有代码执行能力。物理机的执行引擎是建立在处理器、硬件、指令集和操作系统上。而虚拟机的执行引擎是有自己实现的。因此可以自行的制定指令集和执行引擎的结构关系。

个人理解:分为三个部分。分别是介绍运行时分的各个内存区域【程序计数器、java虚拟机栈【局部变量表、操作数栈、动态链接、方法返回地址】、本地方法栈、方法区、堆】。方法的调用【解析、分派】、方法的执行【解析执行、编译执行】

1. 运行时栈帧结构

栈帧是用于虚拟机进行方法调用和方法执行的数据结构。是虚拟机栈的栈元素。这部分内容和运行内存区域中JAVA虚拟机栈中的栈帧结构部分有重叠的部分。一个栈帧包括局部变量表、操作数栈、动态链接和方法返回地址四部分。栈帧需要多大的局部变量表和多深的操作数栈在编译阶段都已经确定的。

Java虚拟机的解释执行引擎称为“基于栈的执行引擎”,其中的栈指的是操作数栈。

程序计数器、虚拟机栈、本地方法栈都是线程级别的。跟着现成的生而生、跟着线程的灭而灭。意味着,每个线程都有自己的java虚拟机栈。该线程中调用的方法都作为一个栈帧,压栈和弹栈。

(1) 局部变量表

主要用来存储方法的参数和方法内部定义的的局部变量。局部变量表是一组值存储空间。

一个方法只有在调用完成后才会释放。因而,如果一个方法之前定义了大内存的对象,但是,在方法后半部分已经不需要这部分内存了。同时,后半部分需要执行很长时间。这种情况下,会造成前半部分创建的大容量的对象既不被使用需要,又因为方法因为没有执行完成而释放。这部分内存会一致占着不能被释放。所以,也可以在方法内,将不需要继续使用的变量赋值为null。可以让垃圾回收器及时的回收。

(2) 操作数栈

操作数栈的深度在编译的时候已经确定。在方法执行的过程中,从局部变量表中获取数据,压栈。需要计算的时候根据运算符号从栈顶弹栈获得数据进行计算,将结果压栈。

(3) 动态链接

在class文件中,一个方法需要调用其它方法。需要将这些方法的符号引用转换成内存地址中的直接引用。而这些符号引用存在方法区的常量池中。

每个栈的栈帧都包含一个指向运行时常量池中该方法的符号引用。持有这个引用的目的是支持方法调用中的动态链接。

这些符号引用一部分会在类加载阶段或者第一次使用的时候转换成了直接引用。这种转换称为静态解析。另一部分将在每一次运行期间转化成直接引用。这部分称为动态链接。

(4) 方法返回地址

当一个方法开始执行时,可能有两种方式退出该方法。正常完成出口异常完成出口。

无论方法采用何种方式退出,在方法退出后都需要返回到方法被调用的位置,程序才能继续执行,方法返回时可能需要在当前栈帧中保存一些信息,用来帮他恢复它的上层方法执行状态。

2. 方法调用

方法调用并不等同于方法执行,核心任务是:确定被调用方法的版本【即调用的是哪一个方法】。不涉及方法内部的具体执行运行过程。

所有方法之间的调用在class文件中存储的是符号引用。而不是具体方法【实际运行时内存布局的入口地址】的直接引用。需要在类加载甚至在运行期间才能确定目标方法的直接引用。

(1) 解析

调用的目标方法都是方法区的常量池中的一个符号引用。如果程序在真正运行之前就可以确定方法调用的版本,并且这个方法调用的版本在运行期间是不会发生变化的。这种情境下,在类加载的解析阶段,会将符号引用转换成直接引用。这种方法的调用称之为解析。

符合“编译期可知,运行期不可变”的要求的方法,主要包括静态方法和私有方法两大类。前者与类直接关联,后者外部不可被访问。他们特点是不可能通过继承或者其它方式重写其它版本。因此,都会通过解析的方式进行方法调用。

解析对应5条方法调用指令:

① Invoke static :调用静态方法

② Invoke special:调用实例构造器<init>方法,私有方法和父类方法。

③ Invoke virtual:调用所有的虚方法。【final修饰的方法,因为不能被覆盖,没有其它版本,所以,无需对方法进行多态选择】

④ Invoke Interface:调用接口方法(多态)

⑤ Invoke dynamic:

解析是一个静态的过程,在类加载的链接阶段的解析阶段中,就会把涉及的符号引全部转换成直接引用。

(2) 分派

① 静态分派

所有依赖静态类型【参数的声明类型来定位方法版本的分派称为静态分派。

静态分派最典型的是重载。在编译阶段,根据参数的静态类型就可以确定执行的是哪个版本的方法。静态分派发生在编译阶段,因此,静态分配的动作不由虚拟机来执行。

② 动态分派

运行期间根据实际类型确定方法执行的版本的分派称为动态分派。

动态分派最典型的就是重写

JVM的invoke virtual指令了,这个指令的解析过程有助于我们更深刻理解重写的本质。该指令的具体解析过程如下

  1. 找到操作数栈栈顶的第一个元素所指向的对象的实际类型,记为C。【获得实际对象的类型】。
  2. 如果在类型C中找到与常量中描述符和简单名称都相符的方法,则进行访问权限的校验,如果通过则返回这个方法的直接引用,查找结束;如果不通过,则返回非法访问异常【在C中找和当前方法匹配的方法】
  3. 如果在类型C中没有找到,则按照继承关系从下到上依次对C的各个父类进行第2步的搜索和验证过程【首先在子类中找,没有再在父类中找。和双亲委派相反,双亲委派优先在父类加载器中处理,而重载优先在子类中匹配
  4. 如果始终没有找到合适的方法,则抛出抽象方法错误的异常。

③ 单分派和多分派

(3) 动态类型语言支持

3. 执行引擎

核心理解虚拟机如果执行方法中的字节码指令集。其实就是基于栈的字节码解释执行引擎做的事情。JAVA虚拟机执行代码的时候,都有解释执行【通过解释器执行】编译执行【通过编译器产生本地代码执行】两种选择

执行引擎:将字节码指令解析/编译为对应平台上本地机器指令。简而言之,执行引擎充当高级语言和机器码之间的翻译者。

其中,执行引擎中 解释器(interpreter)提供解释执行功能。JIT Completer 提供编译执行的功能。

(1) 解释执行

JVM得到字节码之后。通过解析器Interpreter解析成最终的机器码。

(2) 基于栈的指令集和基于寄存器的指令集

基于栈的指令集:将指令集保存在栈中。大部分是零地址指令集,依赖操作数栈进行工作。Java编译器输出的指令集是基于栈的指令集。

PC电脑支持的就是基于寄存器的指令集

(3) 基于栈的解释器执行过程

从指令集顺序执行,将局部变量经过操作数栈,最后在局部变量表中生成。运算的过程是从局部变量表获得数据,然后放入操作数栈。从操作数栈弹出进行计算。之后将结果压栈。

先将数放入操作数栈,然后将操作数栈中的数据弹出放入局部变量表中,这样一步步将局部变量表的变量赋值。运算过程中,从局部变量表中获取数据压入操作数栈中。然后根据指令,从操作数栈中弹出数据进行计算,之后将计算结果压栈。

(4) 编译执行

JVM平台提供一种及时编译技术,及时编译的目的是避免函数被解释执行。而是将整个函数体编译成机器码。每次函数执行时,直接执行编译后的机器码。这种方式能将效率大幅提升。

JVM学习(五) -执行子系统的更多相关文章

  1. jvm学习五: 方法执行过程

    方法执行过程:Java各个大版本更新提供的新特性(需要简单了解)

  2. JVM学习五:JVM之类加载器之编译常量和主动使用

    在学习了前面几节的内容后,相信大家已经对JAVA 虚拟机 加载类的过程有了一个认识和了解,那么本节,我们就继续进一步巩固前面所学知识和特殊点. 一.类的初始化回顾 类在初始化的时候,静态变量的声明语句 ...

  3. JVM学习--(五)垃圾回收器

    上一篇我们介绍了常见的垃圾回收算法,不同的算法各有各的优缺点,在JVM中并不是单纯的使用某一种算法进行垃圾回收,而是将不同的垃圾回收算法包装在不同的垃圾回收器当中,用户可以根据自身的需求,使用不同的垃 ...

  4. JVM学习五:性能监控工具

    一.系统性能监控 系统性能工具用于确定系统运行的整体状态,基本定位问题所在. Linux – uptime • 系统时间 • 运行时间 n 例子中为7分钟 • 连接数 n 每一个终端算一个连接 • 1 ...

  5. JVM学习第三天(JVM的执行子系统)之开篇Class类文件结构

    虽然这几天 很忙,但是学习是不能落下的,也不能推迟,因为如果推迟了一次,那么就会有无数次;加油,come on! Java跨平台的基础: 各种不同平台的虚拟机与所有平台都统一使用的程序存储格式——字节 ...

  6. JVM学习笔记:字节码执行引擎

    JVM学习笔记:字节码执行引擎 移步大神贴:http://rednaxelafx.iteye.com/blog/492667  

  7. java之jvm学习笔记五(实践写自己的类装载器)

    java之jvm学习笔记五(实践写自己的类装载器) 课程源码:http://download.csdn.net/detail/yfqnihao/4866501 前面第三和第四节我们一直在强调一句话,类 ...

  8. 【JVM.8】类加载及执行子系统的案例与实战

    一. 案例分析 1. Tomcat:正统的类加载器架构 主流的Java Web服务器,如Tomcat.Jetty.WebLogic.WebSphere或其他服务器,都实现了自己定义的类加载器(一般都不 ...

  9. JVM性能优化系列-(3) 虚拟机执行子系统

    3. 虚拟机执行子系统 3.1 Java跨平台的基础 Java刚诞生的宣传口号:一次编写,到处运行(Write Once, Run Anywhere),其中字节码是构成平台无关的基石,也是语言无关性的 ...

  10. JVM 的执行子系统

    JVM 的执行子系统. 一.Class类文件结构 1. JVM的平台无关性 与平台无关性是建立在操作系统上,虚拟机厂商提供了许多可以运行在各种不同平台的虚拟机,它们都可以载入和执行字节码,从而实现程序 ...

随机推荐

  1. Linux系统编程—信号集操作函数

    先来回顾一下未决信号集是怎么回事. 信号从产生到抵达目的地,叫作信号递达.而信号从产生到递达的中间状态,叫作信号的未决状态.产生未决状态的原因有可能是信号受到阻塞了,也就是信号屏蔽字(或称阻塞信号集, ...

  2. 栈和队列数据结构的基本概念及其相关的Python实现

    先来回顾一下栈和队列的基本概念: 相同点:从"数据结构"的角度看,它们都是线性结构,即数据元素之间的关系相同. 不同点:栈(Stack)是限定只能在表的一端进行插入和删除操作的线性 ...

  3. C++有子对象的派生类的构造函数

    转载:https://blog.csdn.net/qq1169091731/article/details/50934588?utm_source=blogxgwz6 类的数据成员不但可以是标准型(如 ...

  4. HTML & CSS & JavaScript 从一个表格到一个灰阶颜色表(目录)

    HTML & CSS & JavaScript 从一个表格到一个灰阶颜色表 01 HTML & CSS & JavaScript 从一个表格到一个灰阶颜色表 02 HT ...

  5. 解决mvn clean install的报错The packaging for this project did not assign a file to the build artifact

    解决mvn clean install的报错The packaging for this project did not assign a file to the build artifact

  6. VMware ESXi 客户端连接控制台时,提示“VMRC 控制台连接已断开...正在尝试重新连接”的解决方法

    故障描述: 通过 VMware vSphere Client 连接到安装 VMware ESXi 虚拟环境的主机时,当启动其中的虚拟机后,无法连接到控制台. 选择"控制台"时,控制 ...

  7. shell-的特殊变量-进程状态变量$$ $! $? $_详解

    一:shell的特殊变量-进程状态变量详解  1. 进程状态变量 $$ 获取当前shell的进程号(pid) $! 执行上一个指令的pid,上一个后台运行进程的进程号 $? 获取执行上一个指令的返回值 ...

  8. 多测师讲解自动化测试_rf测试报告_高级讲肖sir

    (一)运行失败 1.1 1.2 用例失败log 2.3Repor 1.4Output (二)运行成功 (三)分析报告 3.1  log: 3.2Report (测试报告) 3.3 Output

  9. 多测师讲解 自动化测试理论(1)_高级讲师肖sir

    自动化测试理论什么是自动化测试?广义的:通过工具或程序替代或辅助人工测试的行为叫自动化测试狭义的:通过工具录制或编写脚本模拟手工测试的过程,通过回放或运行脚本执行测试用例,从而代替人工对系统的功能验证 ...

  10. day22 函数整理

    # 1.计算 年月日时分秒 于现在之间差了多少 格式化时间 # 现在 # 某一个年月日时分秒 参数 # import time # def get_time(old_t,fmt = '%Y-%m-%d ...