1. JRE,JDK

JRE : java运行环境,Java 虚拟机+ Java 核心类库等。

JDK :  JRE + 一系列开发、诊断工具。

2. java字节码

编译器将 Java 程序转换成虚拟机所能识别的指令序列,也称 Java 字节码。

3. 为什么java要在虚拟机里运行?

  • 提供了可移植性
  • java虚拟机提供垃圾回收等功能,使我们免于书写这些无关业务逻辑的代码。

4. Java 虚拟机具体是怎样运行 Java 字节码的?

从虚拟机视角来看

class 文件加载到 Java 虚拟机的方法区中。

实际运行时,虚拟机会执行方法区内的代码。Java 虚拟机在内存中划分出堆和栈来存储运行时数据。  

Java 虚拟机将运行时内存区域划分为五个部分,分别为方法区、堆、PC 寄存器、Java 方法栈和本地方法栈。Java 程序编译而成的 class 文件,需要先加载至方法区中,方能在 Java 虚拟机中运行。

JVM总结-虚拟机怎么执行字节码-LMLPHP

(JVM运行时数据区)

在运行过程中,每当调用进入一个 Java 方法,Java 虚拟机会在当前线程的 Java 方法栈中生成一个栈帧,用以存放局部变量以及字节码的操作数。这个栈帧的大小是提前计算好的,而且 Java 虚拟机不要求栈帧在内存空间里连续分布。

当退出当前执行的方法时,不管是正常返回还是异常返回,Java 虚拟机均会弹出当前线程的当前栈帧,并将之舍弃。

从硬件视角来看,Java 字节码无法直接执行。因此,Java 虚拟机需要将字节码翻译成机器码。

在 HotSpot 里面,上述翻译过程有两种形式:第一种是解释执行,即逐条将字节码翻译成机器码并执行;第二种是即时编译(Just-In-Time compilation,JIT),即将一个方法中包含的所有字节码编译成机器码后再执行。

前者的优势在于无需等待编译,而后者的优势在于实际运行速度更快。HotSpot 默认采用混合模式,综合了解释执行和即时编译两者的优点。它会先解释执行字节码,而后将其中反复执行的热点代码,以方法为单位进行即时编译。JVM总结-虚拟机怎么执行字节码-LMLPHP

5.Java 虚拟机的运行效率究竟是怎么样的?

HotSpot 采用了多种技术来提升启动性能以及峰值性能,刚刚提到的即时编译便是其中最重要的技术之一。

即时编译建立在程序符合二八定律的假设上,也就是百分之二十的代码占据了百分之八十的计算资源。

对于占据大部分的不常用的代码,我们无需耗费时间将其编译成机器码,而是采取解释执行的方式运行;另一方面,对于仅占据小部分的热点代码,我们则可以将其编译成机器码,以达到理想的运行速度。

在计算资源充足的情况下,字节码的解释执行和即时编译可同时进行。编译完成后的机器码会在下次调用该方法时启用,以替换原本的解释执行。

$ echo '
public class Foo {
public static void main(String[] args) {
boolean flag = true;
if (flag) System.out.println("Hello, Java!");
if (flag == true) System.out.println("Hello, JVM!");
}
}' > Foo.java
$ javac Foo.java
$ java Foo
$ java -cp /path/to/asmtools.jar org.openjdk.asmtools.jdis.Main Foo.class > Foo.jasm.1
$ awk 'NR==1,/iconst_1/{sub(/iconst_1/, "iconst_2")} 1' Foo.jasm.1 > Foo.jasm
$ java -cp /path/to/asmtools.jar org.openjdk.asmtools.jasm.Main Foo.jasm
$ java Foo

jvm把boolean当做int来处理

flag = iconst_1 = true

awk把stackframe中的flag改为iconst_2

if(flag)比较时ifeq指令做是否为零判断,常数2仍为true,打印输出

if(true == flag)比较时if_cmpne做整数比较,iconst_1是否等于flag,比较失败,不再打印输出

04-26 16:31
查看更多