Java 代码如何运行
我们写的 Java 代码是高级语言,机器肯定是读不懂的。所以我们需要将它转换成机器能读懂的机器语言 (机器码)。 转换工作主要分为以下几个步骤:
前端编译器
javac 就是前端编译器,可以将 java 文件编译成字节码组成的 class 文件。 java 代码如下:
public class Info {
public static void main(String[] args) {
int a = 1;
System.out.println(a);
}
}
复制代码
执行 javac Info.java 生成 Info.class 文件, 再使用 javap -c Info.class 来查看其中的字节码。
class 中字节码内容如下:

解释器和即时编译器
我们通过 javac 将 java 文件编译成 class 文件,当 jvm 启动加载 class,需要逐条执行字节码指令来完成程序功能。但是程序的执行还是得在机器上,但是机器是不认识字节码的,所以我们需要将字节码转换成机器码,这样才能让机器执行程序。 什么是机器码? 机器码就是用二进制代码表示的计算机能直接识别和执行的一种机器指令的集合。 而解释器和即时编译器 (Just In Time Compiler,JIT) 就是 JVM 中将字节码转化为机器码的工具。
解释器
解释器是一行一行地将字节码解析成机器码,解释到哪就执行到哪,狭义地说,就是 for 循环 100 次,你就要将循环体中的代码逐行解释执行 100 次。当程序需要迅速启动和执行时,解释器可以首先发挥作用,省去编译的时间,立即执行。
即时编译器(JIT)
即时编译器按照我的理解就是:以方法为单位,将热点代码的字节码一次性转为机器码,并在本地缓存起来的工具。避免了部分代码被解释器逐行解释执行的效率问题。 即时编译器分为两种,Client Compiler(C1 编译器) 和 Server Compiler(C2),默认使用的是 C2,因其运行性能更高。
什么是热点代码?
被多次调用的方法和循环体被认定为热点代码。热点代码的判断方法有两种,一是基于采样的热点探测:周期检查每个线程栈顶,统计哪个方法出现次数多,但是不准确;二是基于计数器的热点探测:目前在用,为每个方法建立计数器,统计方法的调用次数。计数器分为方法调用计数器(默认阈值 C1 是 1500 次,C2 是 1w,到达阈值则触发即时编译)和回边计数器(统计一个方法中循环体的执行次数)。 下图为方法调用计数器的执行过程:

目前主流的 HotSpot 虚拟机中默认是采用解释器与其中一个编译器 (C2 编译器) 直接配合的方式将字节码转换成机器码。
运行参数
在执行 java 程序的时候,以下参数是和编译方面的运行及调试参数。
