编译运行单个Java文件
作者:罗上文,微信:Loken1,公众号:FFmpeg弦外之音
众所周知,Java 语言的特点是跨平台,拥有垃圾回收,自动管理内存等特点,Java 的语义比 C++ 更容易理解,可以让开发者更专注于业务层开发。
Java 代码的后缀是 .java
,这些代码首先通过 javac
编译器翻译成 java 字节码。新建一个文件 Hello.java
,内容如下:
public class Hello {
public static void main(String[] args) {
System.out.println("Hello FFmpeg Principle");
}
}
然后使用以下命令编译这个文件:
javac.exe Hello.java
上图中生成的 Hello.class
文件就是 java 的字节码,java 字节码也可以说是 jvm 指令集,这是一种类似于汇编指令的东西。
Hello.class
是一个二进制文件,需要借助 javap
命令来查看 Hello.class
里面的内容,如下:
javap
命令里面的 p 代表 print。
javap.exe -c Hello.class
上图中的 jvm 指令是可以直接被 jvm 虚拟机直接解析运行的,jvm 虚拟机其实 就是 java
命令,如下:
java.exe Hello
java.exe
里面是原生的 CPU 指令,因为我是 AMD 的 CPU,所以 java.exe
里面是 x86 的机器指令。
虽然 jvm 指令一开始是解析运行的,但是从 1996 年,Sun 公司为 java 平台提供了 Just-In-Time(JIT)编译器,可以把 jvm 指令翻译成 本地的 CPU 指令。
JVM 虚拟机会选择性地把 经常运行的 jvm 指令翻译成 本地指令,然后下次再执行这段代码,就不是解析执行了,而是直接运行本地指令,性能会有所提升。
整个过程如下:
上图出自美团的《基本功 | Java即时编译器原理解析及实践》
因此,jvm 指令集是一种虚拟的指令集,一种中间代码。有比较多的基础设施都会采用这种中间代码的设计模式,来让软件达到更好的移植性,例如 NVIDIA 的 PTX 指令集也是一种中间代码,PTX 最终会翻译成 SASS 指令来运行,NVIDIA 也用了 JIT 技术。
由于 jvm 指令集与汇编指令非常类似,所以可以用极低的计算成本把 jvm 指令翻译成 本地的 x86 汇编指令 或者 arm 汇编指令 等等 原生的 CPU 指令集。
一门语言的语法越复杂,或者说越高级的语言,把它翻译成 原生 CPU 指令集的计算成本就越大。