JDK(Java 开发工具包)同样包含了 JRE,并且还附带了一系列开发,诊断工具。
java 为什么要运行在虚拟机里?
语法复杂,抽象程度高。
转换具体操作
主流思路:将 java 程序 转换为能被虚拟机识别的 java 字节码。
为什么叫 java 字节码?
因为 java 字节码的操作码 (opcode) 被固定为一个字节。
一个字节是多大?
托管环境能够做什么?
托管环境能够替我们处理代码中容易出错的部分。广为人知的垃圾回收和数组越界,动态类型,安全权限等等动态监测。
使我们免为书写这些和业务逻辑无关的代码。
java 虚拟机具体是怎么运行字节码的?
字节码怎么怎么翻译成机器码?
两种方式:
HotSpot 是怎样运行的?
HotSpot 默认采用混合模式,综合了解释执行和即时编译两者的优点。他会先执行字节码,而后将其中反复执行的热点代码,已方法为单位进行及时编译。
Java 虚拟机的运行效率究竟是怎样的?
理论上讲,即时编译后的 java 程序的执行效率是可能超过 C++ 程序的。这是因为与静态编译相比,即时编译拥有程序运行时的信息,并且能够根据这个信息作出相应的优化。
举个例子:对于一个抽象方法,尽管它有许多个目标方法,但实际运行中他可能只调用其中一个。这个信息便可以被即时编译器所利用,来规避虚方法调用的开销,从而达到比静态编译的 C++ 程序更高的性能。
HotSpot 的多个即时编译器
之所以引入多个即时编译器,是为了在编译时间和生成代码的执行效率之间进行取舍。
Java7 的分层编译方式
从 Java 7 开始,HotSpot 默认采用分层编译的方式:热点方法首先会被 C1 编译,而后热点方法中的热点会进一步被 C2 编译。
HotSpot 的解释编译和即时编译的分配?
为了不干扰应用的正常运行,HotSpot 的即时编译是放在额外的编译线程中进行的。HotSpot 会根据 CPU 的数量设置编译线程的数目,并且按 1:2 的比例配置给 C1 及 C2 编译器。
在计算资源充足的情况下,字节码的解释执行和即时编译可同时进行。编译完成后的机器码会在下次调用该方法时启用,以替换原本的解释执行。
作业:下载 asmtools.jar [2] ,并在命令行中运行下述指令(不包含提示符 $):
$ 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 vim Foo.java ➜ jvm javac Foo.java ➜ jvm java Foo Hello,Java! Hello,JVM ➜ jvm java -cp asmtools.jar org.openjdk.asmtools.jdis.Main Foo.class > Foo.jasm.1 ➜ jvm awk 'NR==1,/iconst_1/{sub(/iconst_1/,"iconst_2")} 1' Foo.jasm.1 > Foo.jasm ➜ jvm java -cp asmtools.jar org.openjdk.asmtools.jasm.Main Foo.jasm ➜ jvm java Foo Hello,Java!