JVM 简介

简单介绍

JVM

JVM就是java虚拟机,通常说的那些C、C++等语言都是将代码直接编译成CPU能理解的机器码,在不同设备上编出来的机器码不同,而Java语法非常复杂并且抽象程度很高,无法直接在硬件上运行。目前主流做法就是用一款java虚拟机,Java程序在编译时被转换成java虚拟机能够识别的指令序列,叫Java字节码,也就是.class文件,然后再被java虚拟机执行,java虚拟机会将字节码翻译成机器码,最终在硬件上运行。
JVM在不同的操作系统上都有相应的JVM版本,所以如果程序想要在JVM上执行,只需关心如何生成字节码文件即可,而不需要考虑如何适配不同的机器,以及生成相应的机器码。
JVM可以由硬件实现,但是一般使用软件来实现,这样只要设备上装了JVM,就可以执行Java字节码文件。在实现JVM时有一套规范,叫JVM规范,它规定了这个虚拟的计算机各个部分比如堆、栈等实现的一些细节。目前开发者们已经根据这个规范设计出了很多虚拟机,有的虚拟机已经被淘汰,也有一些虚拟机因为有自己适用的领域而存活下来,目前比较完善和使用广泛的就是HotSpot VM,研究性和代表未来的是Graal VM。

JVM翻译Class字节码文件的过程主要有下面两种:

  • 解释执行:逐条将字节码翻译成机器码并执行,无需等待编译,但是运行速度慢。
  • 即时编译:将一个方法中包含的所有字节码编译成机器码后再执行,运行速度快,但是需要等待编译。

JVM除了提供不同设备上统一的运行环境,JVM还有一个重要的功能就是为程序提供托管环境,借助这个托管环境,Java程序开发者只需要注重业务相关开发,而不需要关心内存如何分配和回收、数组越界、动态类型、安全权限等等。

JRE

JRE(Java Runtime Environment, Java运行环境),无论程序生成的Class文件已何种方式,在何种环境运行都离不开JRE,JRE包含了运行Class文件所必须的一些组件,其中主要是虚拟机和核心类库。

JDK

JDK(Java Development Kit),它除了包含JRE,还附带其他一系列开发或者诊断工具,比如编译的工具可以将Java程序编译成Class文件,然后JRE中的JVM就可以执行了;也可以使用javap工具 来查看生成的Class文件长啥样。

HotSpot VM

目前主流的一款由软件实现的Java虚拟机,使用C++语言开发,安装完JDK,在命令行查看java版本时就可以看见它。
在这里插入图片描述
HotSpot用了多种技术来提升性能,其中最重要的就是即时编译:HotSpot翻译Java字节码采用解释执行和即时编译混合模式,它会先解释执行字节码,随后对其中反复执行的热点代码,以方法为单位进行即时编译。这种优化模式是建立在二八定律的假设上,即百分之二十的代码占据了百分之八十的计算资源。在CPU资源充足的情况下,解释执行和即时编译是同时进行的,即时编译好的机器码会在下次改方法被调用时启用,来替换原来的解释执行。

HotSpot 以前内置即时编译器有C1、C2两种,Java7开始C1会先编译热点方法,随后热点中的热点才会被C2进一步编译,HotSpot即时编译是在额外的编译线程中执行,会根据CPU的数量设置编译线程的数目,并且以1:2的比例设置给C1和C2编译器。

  • C1:Client编译器,面向对启动性能有要求的客户端GUI程序,采用的优化手段相对简单,编译时间较短
  • C2:Server编译器,面向对峰值性能有要求的服务端程序,采用的优化手段相对复杂,编译时间较长,但执行效率高

JDK10这个版本对内部进行了重构,比如统一源仓库、统一垃圾收集器接口、统一即时编译器接口等,在这里引入了新的即时编译器Graal
Graal:未来C2的替代者(Server编译器的替代者),C2由C++开发,发展至今已经异常庞大,即使创始人CliffClick也不愿意继续维护。Graal使用java开发,能够将C2中优秀的代码优化技术轻易地移植到Graal上,保持与C2输出相近质量的编译代码,于此同时能够实现在C2上实现异常艰难的优化技术。目前Graal的编译效果已经追平C2,在一些特定测试项中反超C2,比如:部分逃逸分析、激进预测性优化、自定义的预测性假设等。

Graal VM

下世代 Java 虚拟机,2019.05 才发布了第一个 release 版本,内部使用Graal即时编译器,使用java语言开发,能够高效能运行 Java、多语言并行和快速启动

  • 高效能运行 Java:虽然Graal使用Java来开发,但是和HotSpot 使用 C++ 写的 C2 编译器相比在已经预热完毕的前提下能力几乎不相上下,而对于 Scala 应用来说,Graal 编译器更是能达到 10% 以上的优化。
  • 多语言并行: Java 可以在一个运行期内,同时使用多种语言,目前支持的有Python、R、JavaScript,后续会陆续增加
public class GraalTest{
    public static void main(String[] args) {
        System.out.println("Hello World from Java!");
        Context context = Context.newBuilder().allowAllAccess(true).build();
        context.eval("js", "print('Hello World from js!');");
        context.eval("python", "print('Hello World from Python!')");
        context.eval("ruby", "puts 'Hello World from R!'");
    }
}
  • 快速启动:采用AOT (Ahead-of-time compile:提前编译)技术,来更快速的启动一个 java 应用。在编译期时,会把所有相关的东西,包含一个基底的 VM,一起编译成机器码,这个基底 VM 是 GraalVM 内部才有的东西,它只包含最基本的线程排成机制、垃圾回收,尽可能的缩小必要的 jvm 体积。但是会带来两个问题:
  1. 由于他只包含必须的小体积的JVM,所以JVM一些代码优化无法使用
  2. 由于他编译器直接生成机器码,所以无法动态加载,目前的做法是把所以可能用的的一起编译。

JVM执行Java字节码

JVM中关于运行Java字节码主要有三块分区(不是全部):方法区、堆、栈

方法区:加载需要执行的.class文件,运行时JVM会执行方法区内的代码

堆、栈:堆和栈用来存储运行时数据

栈:主要被分为三个部分

  • 面向Java方法的Java方法栈
  • 面向本地方法的本地方法栈(C++写的native方法)
  • 存放各个线程执行位置的PC寄存器

在运行过程中,每当调用一个方法,JVM就会在当前线程的Java方法栈中生成一个栈帧,来存放局部变量和字节码操作数,这个栈帧的大小是提前计算好的,内存空间不需要连续分布。当该方法执行完(正常返回或者异常退出),当前栈帧就会被弹出并且被舍弃。

在这里插入图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值