1. 2011年,JDK7发布,1.7u4中,开始启用新的垃圾回收器G1(但是不是默认)。
    1. 2017年,发布JDK9G1成为默认GC,代替CMS。(一般公司使用jdk8的时候,会通过参数,指定GCG1)
    1. 2018年,发布JDK11,带来了革命性ZGC,性能比较强。

虚拟机介绍

虚拟机,就是虚拟的计算机,可以执行一系列虚拟计算机指令,大体上可以分为系统虚拟机和程序虚拟机。它们运行时,都会受到虚拟机提供的资源的限制。

  • 系统虚拟机:仿真模拟系统的,比如Visual BoxVMware
  • 程序虚拟机:为执行单个计算机程序设计的,比如Java虚拟机。

JAVA虚拟机

Java虚拟机是一台执行字节码的虚拟机计算机,但是字节码不一定是由Java语言编译而成。但是只要使用这一套虚拟机规则的语言,就可以享受到跨平台,垃圾收集以及可靠的即时编译器。JVM和硬件之间没有直接的交互。

  • 一次编译,到处运行。
  • 自动内存管理
  • 自动垃圾回收

下面是ava平台文档中Java概念图的描述,可以看出javac命令在JDK中,也就是将.java文件编译成为.class文件,这个就是前端编译器,将源文件编译成为字节码。这个编译器不在JRE中,也说明了JRE不包括编译环境。

JRE和JDK都包括了JVM虚拟机。JRE是运行时环境,而JDK包含了开发环境。

JDK7 中java家族的结构组成 : https://docs.oracle.com/javase/7/docs/

JDK7 中java家族的结构组成 : https://docs.oracle.com/javase/8/docs/

JVM结构

上面的图主要包括三部分:类加载器,运行时数据区,执行引擎。

类加载器,主要是将Class文件(已经经过前端编译器编译后的字节码文件),加载到运行时数据区,生成Class对象,这个过程会设计加载,链接,初始化等过程。

运行时区域主要分为:

  • 线程私有(每个线程有一份):

    • 程序计数器:Program Count Register,线程私有,没有垃圾回收
    • 虚拟机栈:VM Stack,线程私有,没有垃圾回收
    • 本地方法栈:Native Method Stack,线程私有,没有垃圾回收
  • 线程共享:
    • 方法区:Method Area,以HotSpot为例,JDK1.8后元空间取代方法区,有垃圾回收。
    • 堆:Heap,垃圾回收最重要的地方。

执行引擎主要包括解释器和即时编译器(热点代码提前编译好,这是后端编译器),垃圾回收器。字节码文件不能直接被机器识别,所以需要执行引擎来做转换。

Java代码执行流程

Java代码变成字节码文件的过程中,其实包含了词法分析,语法分析,语法树,语义分析等一系列操作。

在执行引擎中,有JIT编译器,也就是第二次编译的过程会发生在这里,会将热点代码编译成为机器指令,是按照方法的维度,缓存起来(放在方法区),也称之为CodeCache

JVM架构模型

Java编译器主要是基于栈的指令集架构,个人觉得主要原因是可移植性决定的,JVM需要跨平台。指令集架构主要有两种:

  • 基于栈的指令集架构:一个方法相当于一个入栈的操作,执行完相当于出栈操作。
  • 基于寄存器的指令集架构

基于栈的指令集架构的特点

主要特点:

  • 设计实现简单,适用于资源受限的系统,比如机顶盒,小玩具上。
  • 避开寄存器分配难题:使用零地址指令方式分配。
  • 指令流中大部分都是零地址指令,执行过程依赖操作栈,指令集更小(零地址),编译器容易实现。
  • 不需要硬件支持,可移植性强,容易实现跨平台。

基于寄存器架构的特点

  • 典型应用是x86的二进制指令集
  • 依赖于硬件,可移植性差
  • 性能好,执行效率高
  • 更少指令执行一项操作
  • 大部分情况下,寄存器的架构,一,二,三地址指令为主,而基于栈的指令集却是以零地址指令为主。

说明:什么叫零地址指令,一地址指令,二地址指令?

零地址指令只有操作码,没有操作数。这种指令有两种情况:一是无需操作数,另一种是操作数为默认的(隐含的),默认为操作数在寄存器中,指令可直接访问寄存器。

  • 三地址指令:一般地址域中A1、A2分别确定第一、第二操作数地址,A3确定结果地址。下一条指令的地址通常由程序计数器按顺序给出。

  • 二地址指令:地址域中A1确定第一操作数地址,A2同时确定第二操作数地址和结果地址。

  • 单地址指令:地址域中A 确定第一操作数地址。固定使用某个寄存器存放第二操作数和操作结果。因而在指令中隐含了它们的地址。

  • 零地址指令:在堆栈型计算机中,操作数一般存放在下推堆栈顶的两个单元中,结果又放入栈顶,地址均被隐含,因而大多数指令只有操作码而没有地址域。

栈数据结构,一般只有入栈和出栈,所以操作的地方只有栈顶元素,所以位置是确定的,不需要地址。

例子

执行2+3的操作,如果是基于栈的计算流程:

iconst_2 // 常量2入栈
istore_1
iconst_3 // 常量3入栈
istore_2
iload_1
iload_2
iadd // 常量2,3出栈,执行相加
istore_0 // 结果5入栈

基于寄存器的计算流程:

mov eax,2   //将eax寄存器的值设置为2
add eax,3 // 将eax寄存器的值加3

从上面的例子可以看出来,基于栈的寄存器的指令更小,但是基于寄存器的指令更少。

我们可以通过一个简单程序看一下:

public class StackStructTest {
public static void main(String[] args) {
int i = 2 + 3;
}
}

编译后,切换到class目录下,使用命令反编译:

java -v StackStructTest.class

看到字节码的模块,可以看到前面有iconst_5,其实5就是2+3的结果,也就是编译期间就会直接把2+3变成5,不会在运行的时候才去计算,这个是因为23都是常量。

这个现象称之为编译期的常量折叠

但是如果我们把代码成下面这种情况呢?

        int i = 2;
int j = 3;
int k = i + j;

反编译出来的指令:

const意思是constant(常量),storestoreage寄存器。

 stack=2, locals=4, args_size=1
0: iconst_2 // 2是个常量
1: istore_1 // 2加载到1号操作数栈
2: iconst_3 // 3是一个产量
3: istore_2 // 3加载到2号操作数栈
4: iload_1 // 将1号操作数栈取出,加载进来
5: iload_2 // 将2号操作数栈取出,加载进来
6: iadd // 两者相加
7: istore_3 // 结果存储到索引为3号操作数栈中
8: return

也就是栈架构的JVM,需要 8 条指令才能完成上面的变量相加计算。

栈架构总结

由于跨平台特性,Java指令基于栈来设计,因为不同的CPU架构不同,优点是跨平台,指令集小,编译器容易实现。缺点是性能下降,实现同样功能需要更多指令。

【作者简介】

秦怀,公众号【秦怀杂货店】作者,技术之路不在一时,山高水长,纵使缓慢,驰而不息。个人写作方向:Java源码解析,JDBC,Mybatis,Spring,redis,分布式,剑指Offer,LeetCode等,认真写好每一篇文章,不喜欢标题党,不喜欢花里胡哨,大多写系列文章,不能保证我写的都完全正确,但是我保证所写的均经过实践或者查找资料。遗漏或者错误之处,还望指正。

2020年我写了什么?

开源编程笔记

JVM笔记 -- JVM的发展以及基于栈的指令集架构的更多相关文章

  1. 基于栈的指令集与基于寄存器的指令集的区别,JVM指令集实例

    现代JVM在执行Java代码的时候,通常都会将解释执行与编译执行两者结合起来 所谓解释执行,就是通过解释器来读取字节码,遇到相应的指令就去执行该指令. 所谓编译执行,就是通过即时编译器(Just In ...

  2. 基于栈的指令集与基于寄存器的指令集详细比对及JVM执行栈指令集实例剖析

    基于栈的指令集与基于寄存器的指令集详细比对: 这次来学习一些新的概念:关于Java字节码的解释执行的一种方式,当然啦是一些纯理论的东东,但很重要,在之后会有详细的实验来对理论进行巩固滴,下面来了解一下 ...

  3. JVM笔记 -- JVM经历了什么?

    Sun Classic VM 世界上第一款商用 Java 虚拟机,JDK1.4 已经淘汰. 内部只有解释器,可以自己外挂JIT编译器,但是二者只能使用其一,不能配合工作. hotspot 内置了该虚拟 ...

  4. JVM笔记 -- JVM的生命周期介绍

    Github仓库地址:https://github.com/Damaer/JvmNote 文档地址:https://damaer.github.io/JvmNote/ JVM生命周期 启动 执行 退出 ...

  5. Dubbo入门到精通学习笔记(七):基于Dubbo的分布式系统架构介绍(以第三方支付系统架构为例)、消息中间件的作用介绍

    文章目录 架构简单介绍 消息中间件在分布式系统中的作用介绍 消息中间件的定义 消息中间件的作用 应用场景 JMS(Java Message Service) JMS消息模型 实现了JMS规范的消息中间 ...

  6. jvm 字节码执行 (二)动态类型支持与基于栈的字节码解释执行

    动态类型语言 动态类型语言的关键特征是它的类型检查的主体过程是在运行期而不是编译期. 举例子解释“类型检查”,例如代码: obj.println("hello world"); 假 ...

  7. 读书笔记-JVM

    局部变量表(虚拟机栈中的一部分)在编译期完成分配,运行期不会再改变大小: 每个方法对应一个栈帧(存储局部变量表.操作数栈.动态链接.方法出口等),栈帧被存储到虚拟机栈中,每个线程对应一个虚拟机栈,方法 ...

  8. JVM解毒——JVM与Java体系结构

    你是否也遇到过这些问题? 运行线上系统突然卡死,系统无法访问,甚至直接OOM 想解决线上JVM GC问题,但却无从下手 新项目上线,对各种JVM参数设置一脸懵逼,直接默认,然后就JJ了 每次面试都要重 ...

  9. 【JVM】肝了一周,吐血整理出这份超硬核的JVM笔记(升级版)!!

    写在前面 最近,一直有小伙伴让我整理下关于JVM的知识,经过十几天的收集与整理,初版算是整理出来了.希望对大家有所帮助. JDK 是什么? JDK 是用于支持 Java 程序开发的最小环境. Java ...

随机推荐

  1. Codeforces Round #529 (Div. 3) E. Almost Regular Bracket Sequence (思维,模拟栈)

    题意:给你一串括号,每次仅可以修改一个位置,问有多少位置仅修改一次后所有括号合法. 题解:我们用栈来将这串括号进行匹配,每成功匹配一对就将它们消去,因为题目要求仅修改一处使得所有括号合法,所以栈中最后 ...

  2. 2017, X Samara Regional Intercollegiate Programming Contest B.Pursuing the Happiness (string函数)

    题意:给你一个字符串,可以交换两个字符的位置,问操作后能否在字符串中找到子串\("happiness"\),如果不能,输出交换的两个位置. 题解:这题其实用string中的find ...

  3. jdk8下的接口和抽象类

    接口 在java8中,接口可以定义变量和方法,其中变量必须为 public && static && final: 方法必须为public && (ab ...

  4. Kubernets二进制安装(12)之部署Node节点服务的kube-Proxy

    kube-proxy是Kubernetes的核心组件,部署在每个Node节点上,它是实现Kubernetes Service的通信与负载均衡机制的重要组件; kube-proxy负责为Pod创建代理服 ...

  5. Maven与Nexus3.x环境构建详解

    一.Maven介绍Apache Maven是一个创新的软件项目管理和综合工具.Maven提供了一个基于项目对象模型(POM)文件的新概念来管理项目的构建,可以从一个中心资料片管理项目构建,报告和文件. ...

  6. Linux Schedule Cron All In One

    Linux Schedule Cron All In One 定时任务 / 定时器 GitHub Actions Scheduled events Cron syntax has five field ...

  7. js & while & do while

    js & while & do while https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Stat ...

  8. css & circle & shapes

    css & circle & shapes css-tricks circle https://css-tricks.com/the-shapes-of-css/ https://cs ...

  9. css & box-shadow & outline

    css & box-shadow & outline CSS3 box-shadow : 4 sides symmetry https://learning.xgqfrms.xyz/C ...

  10. nodejs 在windows10中设置动态(视频)壁纸

    github 项目地址 node版本 λ node -v v12.16.2 main.js const ffi = require("@saleae/ffi"); const ch ...