为什么解释Java字节码?
据我所知,Java编译为Java字节码,然后可以由任何运行Java的机器为其特定的CPU解释。Java使用JIT来解释字节码,我知道它这样做的速度非常快,但是为什么语言设计人员在检测到它正在运行的特定机器时不静态编译为机器指令呢?字节码是否在每次通过代码时都得到解释?
据我所知,Java编译为Java字节码,然后可以由任何运行Java的机器为其特定的CPU解释。Java使用JIT来解释字节码,我知道它这样做的速度非常快,但是为什么语言设计人员在检测到它正在运行的特定机器时不静态编译为机器指令呢?字节码是否在每次通过代码时都得到解释?
最初的设计是在“一次编译,随处运行”的前提下。因此,虚拟机的每个实现者都可以运行编译器生成的字节码。
在《编程策划者》(Masterminds for Programming)一书中,James Gosling解释说:
詹姆斯:没错。如今,我们几乎总是击败真正优秀的C和C++编译器。当您转到动态编译器时,当编译器在最后一刻运行时,您将获得两个优势。一个是你确切地知道你正在运行什么芯片组。很多时候,当人们编译一段C代码时,他们必须编译它以在通用的x86架构上运行。您获得的二进制文件中几乎没有一个特别适合它们中的任何一个。你下载 Mozilla 的最新副本,它几乎可以在任何 Intel 架构 CPU 上运行。几乎只有一个Linux二进制文件。它非常通用,它是用GCC编译的,GCC不是一个很好的C编译器。
当 HotSpot 运行时,它确切地知道您正在运行哪个芯片组。它确切地知道缓存是如何工作的。它确切地知道内存层次结构是如何工作的。它确切地知道所有管道联锁在CPU中的工作方式。它知道这个芯片得到了什么指令集扩展。它可以精确地针对您使用的机器进行优化。然后它的另一半是它实际上看到了应用程序正在运行。它能够有统计数据来知道哪些事情是重要的。它能够内联C编译器永远无法做到的事情。在Java世界中内联的那种东西非常惊人。然后,您可以按照存储管理与现代垃圾回收器一起工作的方式来附加它。使用现代垃圾回收器,存储分配非常快。
Java通常被编译成机器指令;这就是实时 (JIT) 编译。但默认情况下,Sun 的 Java 实现仅对运行频率足够高的代码执行此操作(因此,仅执行一次的启动和关闭字节码仍会被解释为防止 JIT 开销)。