1.为什么Java要在虚拟机中运行
java是一门高级语言,语法非常复杂,抽象程度非常高,因此直接在硬件上运行并不现实,因此再运行之前,我们对其进行转换。转换的思路就是将代码编译为虚拟机能够识别的指令序列(java字节码,之所以这样命名是由于java字节码指令的操作码被固定为一个字节)
java虚拟机:虚拟机可以由硬件实现也可以由软件(jdk)实现,目前windows和linux大部分采取的软件实现
其中虚拟机带来的好处如下:
2.Java虚拟机如何运行Java字节码
下面所述都是以标准JDK的HotSpot为例
虚拟机视角
将编译而成的字节码文件加载到虚拟机中,加载后的类会放置在运行时的方法区(Method Area)中,实际运行中,虚拟机会执行方法区内的代码
虚拟机将栈细分为面向Java方法的Java方法栈,面向本地方法的本地方法(用C++写的native方法,在jdk源码中有大量使用)栈,以及存放各个线程执行位置的PC寄存器

由上图我们可以看到还有线程私有的方法区,那么这里的方法区是拿来干什么的呢?
在运行过程中,每当调用一个方法,会给当前线程的java方法栈中生成一个栈帧,用于存放局部变量和字节码的操作数。栈帧大小是提前计算好了,不需要分配连续的空间。退出当前执行的方法时,不管是正常返回还是异常返回,Java虚拟机都会执行当前线程的该方法的弹栈操作
硬件视角
Java字节码无法直接执行,因此虚拟机需要将字节码翻译为机器码
对于Hot Spot而言,上述翻译过程,有两个办法:
- 解释执行:逐条将字节码翻译为机器码并执行,翻译和执行是同步的,所以说无需等待编译
- 即时编译(Just-In-Time compilation,JIT):将一个方法中包含的所有字节码编译成机器码再执行,先翻译再执行,能获得到运行时的信息,因此运行效率有时候会优于C++
前者的优势在于无需等待编译,后者的优势在于实际运行速度更快。Hot Spot默认采用混合模式,综合了解释执行和即时编译两者的优点。它会先解释执行字节码,而后将其中反复执行的热点代码,以方法为单位进行即时编译

3.Java虚拟机的运行效率
Hot Spot对于大部分不常用的代码采取解释执行的方式运行,对于常用的代码将其编译成字节码,以达到理想的运行速度
Hot Spot内置两个即时编译器:C1、C2
- C1:又叫做Client编译器,面对的是对启动性能有要求的客户端GUI程序,编译时间较短
- C2:又叫做Server编译器,面对的是对峰值性能有要求的服务端程序,优化手段比较复杂,编译时间较长。但生成代码的执行效率高
Java7开始采用分层编译:
- 热点方法首先会被C1编译,热点方法中的热点会进一步被C2编译
- 为了不干扰正常应用的运行,即时编译会被放在额外的编译线程运行,HotSpot 会根据 CPU 的数量设置编译线程的数目,并且按 1:2 的比例配置给 C1 及 C2 编译器
- 资源充足的情况下,解释执行和即时编译同时进行,编译完成的机器码会在下次调用时启用,替换原本的解释执行