在 Java 中,JVM 能够了解的代码就叫做字节码(即扩展名为 .class
的文件),它不面向任何特定的处理器,只面向虚拟机。Java 言语经过字节码的方法,在必定程度上解决了传统解说型言语履行功率低的问题,一起又保留了解说型言语可移植的特点。所以, Java 程序运转时相对来说仍是高效的(不过,和 C++,Rust,Go 等言语仍是有必定距离的),而且,由于字节码并不针对一种特定的机器,因而,Java 程序无须重新编译便可在多种不同操作系统的核算机上运转。
Java 程序从源代码到运转的进程如下图所示:
我们需要分外注意的是 .class->机器码
这一步。在这一步 JVM 类加载器首先加载字节码文件,然后经过解说器逐行解说履行,这种方法的履行速度会相对比较慢。而且,有些方法和代码块是常常需要被调用的(也便是所谓的热门代码),所以后边引进了 JIT(just-in-time compilation) 编译器,而 JIT 属于运转时编译。当 JIT 编译器完成第一次编译后,其会将字节码对应的机器码保存下来,下次能够直接运用。而我们知道,机器码的运转功率肯定是高于 Java 解说器的。这也解说了我们为什么常常会说 Java 是编译与解说共存的言语 。
HotSpot 采用了慵懒评价(Lazy Evaluation)的做法,依据二八定律,耗费大部分系统资源的只有那一小部分的代码(热门代码),而这也便是 JIT 所需要编译的部分。JVM 会依据代码每次被履行的状况收集信息并相应地做出一些优化,因而履行的次数越多,它的速度就越快。JDK 9 引入了一种新的编译模式 AOT(Ahead of Time Compilation),它是直接将字节码编译成机器码,这样就避免了 JIT 预热等各方面的开销。JDK 支持分层编译和 AOT 协作运用。
为什么不全部运用 AOT 呢?
AOT 能够提早编译节省启动时间,那为什么不全部运用这种编译方法呢?
长话短说,这和 Java 言语的动态特性有千丝万缕的联系了。举个比如,CGLIB 动态代理运用的是 ASM 技能,而这种技能大致原理是运转时直接在内存中生成并加载修改后的字节码文件也便是 .class
文件,假如全部运用 AOT 提早编译,也就不能运用 ASM 技能了。为了支持类似的动态特性,所以选择运用 JIT 即时编译器。
相关阅读:Java根底常见面试题总结(上)