Java 虚拟机概要

164 阅读4分钟

什么是 Java 虚拟机?

JVM 是 Java Virtual Machine(Java 虚拟机)的缩写,是通过在实际的计算机上仿真模拟各种计算机功能来实现的。由一套字节码指令集、一组寄存器、一个栈、一个垃圾回收堆和一个存储方法域等组成。JVM 屏蔽了与操作系统平台相关的信息,使得 Java 程序只需要生成在 Java 虚拟机上运行的目标代码(字节码),就可在多种平台上不加修改的运行,这也是 Java 能够“一次编译,到处运行的”原因。

Java 虚拟机的意义

java 代码是无法直接被机器运行,需要经过

  1. 通过 javac 命令将 java 代码编译为 Java 虚拟机可以认识的.class 文件(Java 字节码)
  2. 然后在运行时再由 Java 虚拟机内嵌的解释器将 Java 字节码编译为机器可以运行的机器码。但是常见的 jdk 都提供了 JIT 编译器,JIT 编译器能够在运行时将热点代码编译为机器码,等下次执行到改代码时就可以直接运行。
# 机器码和Java字节码
# 最左列是偏移;中间列是给虚拟机读的机器码;最右列是给人读的代码
0x00: b2 00 02         getstatic java.lang.System.out
0x03: 12 03           ldc "Hello, World!"
0x05: b6 00 04         invokevirtual java.io.PrintStream.println
0x08: b1               return

Java 虚拟机是由 c 语言编写,在现在常见的平台(如 windows、linux、mac)上都提供了软件实现,也就是:“一次编写,到处运行”。 Java 虚拟机还提供了一个托管环境,比如内存管理、垃圾回收等。 Java 虚拟机还提供了动态监测,如数组越界、动态类型、安全权限等。 Java 虚拟机的好处:1.跨平台 2.托管管理 3.简化开发者工作

Java 虚拟机运行 class 文件过程

  1. 虚拟机会通过类加载器(Class-Loader)加载字节码到 Java 虚拟机中

  2. 加载后的 Java 类会存放于方法区(Method Area)。实际运行时,虚拟机会执行方法区内的代码。

    1. 执行时需要将 Java 字节码翻译为机器码。有解释执行即时编译两种
    2. 解释执行是在执行时一行一行的翻译给机器,所以无须等待编译。
    3. 即时编译(JIT)是将一个方法中包含的所有字节码编译成字节码后再执行,但是等下次再执行就无须编译了。
    4. 现在流行 jdk 默认采用混合模式,先会解释执行字节码,然后将其中反复执行的热点代码,以方法为单位进行即时编译。
  3. 在运行过程中,每进入一个 Java 方法,虚拟机会在当前现成的 Java 方法栈中生成一个栈针,用来存放局部变量以及字节码的操作数。

  4. 当推出当前执行的方法时,不管正常还是异常返回 Java 虚拟机都会弹出当前线程的当前栈针,将之舍弃。

Java 虚拟机在运行效率上的优化

即时编译建立在程序符合二八定律的假设上,也就是说百分之二十的代码占据了百分之八十的资源。要优化的部分就是那部分占据小的热点代码,我们将其编译成机器码,提高运行效率。即时编译后的代码理论上可能超过 c++。 HotSpot 内置了 C1、C2 和 Graal 编译器。C1 优化手段相对简单,编译时间也较短,一般用在 GUI 客户端上;C2 优化手段复杂,编译时间较长,一般用在 server 端。 在 Java7 开始,HotSpot 默认采用即时编译的方式,热点方法首先被 C1 编译,而后热点中的热点会进一步被 C2 编译。且为了不干扰程序运行,即时编译是放在额外的编译线程中进行的。 热点代码一般有两种探测方式:1.基于采样的热点探测 2.基于计数器的热点探测。一般采用的都是基于计数器的热点探测。基于计数器的热点探测又分为调用计数器,回边计数器。