JVM学习(五) -执行子系统
虚拟机和物理机的区别。两种都有代码执行能力。物理机的执行引擎是建立在处理器、硬件、指令集和操作系统上。而虚拟机的执行引擎是有自己实现的。因此可以自行的制定指令集和执行引擎的结构关系。
个人理解:分为三个部分。分别是介绍运行时分的各个内存区域【程序计数器、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指令了,这个指令的解析过程有助于我们更深刻理解重写的本质。该指令的具体解析过程如下
- 找到操作数栈栈顶的第一个元素所指向的对象的实际类型,记为C。【获得实际对象的类型】。
- 如果在类型C中找到与常量中描述符和简单名称都相符的方法,则进行访问权限的校验,如果通过则返回这个方法的直接引用,查找结束;如果不通过,则返回非法访问异常【在C中找和当前方法匹配的方法】
- 如果在类型C中没有找到,则按照继承关系从下到上依次对C的各个父类进行第2步的搜索和验证过程【首先在子类中找,没有再在父类中找。和双亲委派相反,双亲委派优先在父类加载器中处理,而重载优先在子类中匹配】
- 如果始终没有找到合适的方法,则抛出抽象方法错误的异常。
③ 单分派和多分派
(3) 动态类型语言支持
3. 执行引擎
核心理解虚拟机如果执行方法中的字节码指令集。其实就是基于栈的字节码解释执行引擎做的事情。JAVA虚拟机执行代码的时候,都有解释执行【通过解释器执行】和编译执行【通过编译器产生本地代码执行】两种选择。
执行引擎:将字节码指令解析/编译为对应平台上本地机器指令。简而言之,执行引擎充当高级语言和机器码之间的翻译者。
其中,执行引擎中 解释器(interpreter)提供解释执行功能。JIT Completer 提供编译执行的功能。

(1) 解释执行
JVM得到字节码之后。通过解析器Interpreter解析成最终的机器码。
(2) 基于栈的指令集和基于寄存器的指令集
基于栈的指令集:将指令集保存在栈中。大部分是零地址指令集,依赖操作数栈进行工作。Java编译器输出的指令集是基于栈的指令集。
PC电脑支持的就是基于寄存器的指令集。
(3) 基于栈的解释器执行过程
从指令集顺序执行,将局部变量经过操作数栈,最后在局部变量表中生成。运算的过程是从局部变量表获得数据,然后放入操作数栈。从操作数栈弹出进行计算。之后将结果压栈。
先将数放入操作数栈,然后将操作数栈中的数据弹出放入局部变量表中,这样一步步将局部变量表的变量赋值。运算过程中,从局部变量表中获取数据压入操作数栈中。然后根据指令,从操作数栈中弹出数据进行计算,之后将计算结果压栈。
(4) 编译执行
JVM平台提供一种及时编译技术,及时编译的目的是避免函数被解释执行。而是将整个函数体编译成机器码。每次函数执行时,直接执行编译后的机器码。这种方式能将效率大幅提升。
JVM学习(五) -执行子系统的更多相关文章
- jvm学习五: 方法执行过程
方法执行过程:Java各个大版本更新提供的新特性(需要简单了解)
- JVM学习五:JVM之类加载器之编译常量和主动使用
在学习了前面几节的内容后,相信大家已经对JAVA 虚拟机 加载类的过程有了一个认识和了解,那么本节,我们就继续进一步巩固前面所学知识和特殊点. 一.类的初始化回顾 类在初始化的时候,静态变量的声明语句 ...
- JVM学习--(五)垃圾回收器
上一篇我们介绍了常见的垃圾回收算法,不同的算法各有各的优缺点,在JVM中并不是单纯的使用某一种算法进行垃圾回收,而是将不同的垃圾回收算法包装在不同的垃圾回收器当中,用户可以根据自身的需求,使用不同的垃 ...
- JVM学习五:性能监控工具
一.系统性能监控 系统性能工具用于确定系统运行的整体状态,基本定位问题所在. Linux – uptime • 系统时间 • 运行时间 n 例子中为7分钟 • 连接数 n 每一个终端算一个连接 • 1 ...
- JVM学习第三天(JVM的执行子系统)之开篇Class类文件结构
虽然这几天 很忙,但是学习是不能落下的,也不能推迟,因为如果推迟了一次,那么就会有无数次;加油,come on! Java跨平台的基础: 各种不同平台的虚拟机与所有平台都统一使用的程序存储格式——字节 ...
- JVM学习笔记:字节码执行引擎
JVM学习笔记:字节码执行引擎 移步大神贴:http://rednaxelafx.iteye.com/blog/492667
- java之jvm学习笔记五(实践写自己的类装载器)
java之jvm学习笔记五(实践写自己的类装载器) 课程源码:http://download.csdn.net/detail/yfqnihao/4866501 前面第三和第四节我们一直在强调一句话,类 ...
- 【JVM.8】类加载及执行子系统的案例与实战
一. 案例分析 1. Tomcat:正统的类加载器架构 主流的Java Web服务器,如Tomcat.Jetty.WebLogic.WebSphere或其他服务器,都实现了自己定义的类加载器(一般都不 ...
- JVM性能优化系列-(3) 虚拟机执行子系统
3. 虚拟机执行子系统 3.1 Java跨平台的基础 Java刚诞生的宣传口号:一次编写,到处运行(Write Once, Run Anywhere),其中字节码是构成平台无关的基石,也是语言无关性的 ...
- JVM 的执行子系统
JVM 的执行子系统. 一.Class类文件结构 1. JVM的平台无关性 与平台无关性是建立在操作系统上,虚拟机厂商提供了许多可以运行在各种不同平台的虚拟机,它们都可以载入和执行字节码,从而实现程序 ...
随机推荐
- 033 01 Android 零基础入门 01 Java基础语法 03 Java运算符 13 运算符和表达式知识点总结
033 01 Android 零基础入门 01 Java基础语法 03 Java运算符 13 运算符和表达式知识点总结 本文知识点:运算符和表达式知识点总结 前面学习的几篇文都是运算符和表达式相关的知 ...
- 达梦数据库_DM8配置MPP主备
为了提高MPP系统可靠性,克服由于单节点故障导致整个系统不能继续正常工作,DM 在普通的MPP系统基础上,引入主备守护机制,将MPP节点作为主库节点,增加备库作为备份节点,必要时可切换为主库代替故障节 ...
- Varnish 6.2.2 的介绍与安装
一.简介 Varnish 是一款高性能且开源的反向代理服务器和 HTTP 加速器,其采用全新的软件体系机构,和现在的硬件体系紧密配合,与传统的 Squid 相比,Varnish 具有性能更高.速度更快 ...
- es6深层次数组深拷贝
let arr = [ { label: '1', children: [1, 2] } ] let a = [{...arr[0]}] ...
- 不要以为Bug写的好就是好程序员,其实这只占不到15%!
最近和一位从事多年架构工作的技术哥们见面,聊到了近期面试程序员的一些经历,谈到了"如何判断程序员水平高低"这个话题,颇有些感触,觉得有价值,因此花了些时间整理.分享给大家. 正 ...
- 【纯水题】CF 833A The Meaningless Game
题目大意 洛谷链接 现在两个人做游戏,每个人刚开始都是数字\(1\),谁赢了就能乘以\(k^2\),输的乘以\(k\),现在给你最终这两个人的得分,让你判断是否有这个可能,有可能的话输出Yes,否则输 ...
- Centos定时备份 MySQL数据库
一.编写数据库备份脚本 backupmysql.sh #!/bin/bash # Name:bakmysql.sh # This is a ShellScript For Auto DB Backup ...
- Python虚拟环境操作
1.安装pip install virtualenvwrapperpip install virtualenvwrapper-win #Windows使用该命令 2.创建一个文件夹,用来保存虚拟环境目 ...
- Business Partner - 供应商与客户的集成 - S/4HANA(2)
配置 BP配置 激活BP的PPO请求 Cross-Application Components->Master Data Synchronization->Master Data Sync ...
- 痞子衡嵌入式:MCUBootUtility v2.4发布,轻松更换Flashloader文件
-- 痞子衡维护的NXP-MCUBootUtility工具距离上一个版本(v2.3.1)发布过去2个月了,这一次痞子衡为大家带来了版本升级v2.4.0,这个版本主要有一个非常重要的更新需要跟大家特别说 ...