从Java8开始,JVM默认采用分层编译的方式。它将执行分为五个层次,分为0层解释执行,1层执行没有profiling的C1代码,2层执行部分profiling的C1代码,3层执行全部profiling的C1代码,和4层执行C2代码。
    通常情况下,方法会首先被解释执行,然后被3层的C1编译,最后被4层的C2编译。
    1层和4层是终止态。

    通常来说,代码会被JVM解释执行,反复执行的热点代码则会被即时编译成为机器码,直接运行在底层硬件上。

    JVM根据方法的调用次数以及循环回边的执行次数来触发即时编译。

    OSR编译
    以循环为单位的即时编译,叫做On-Stack_Replacement(OSR)编译。
    在程序执行过程中,动态地替换掉Java方法栈桢,使得程序能够在非方法入口处进行解释执行和编译后的代码之间的切换。

    profiling 是指在程序执行过程中,收集能够反映程序执行状态的数据。通常情况下,解释执行过程中仅收集方法的调用次数以及循环回边的执行次数。
    基于分支profile优化,即时编译器可以将从未执行过的分支剪掉,节省编译时间以及内存空间。还可以根据分支profile,计算每一条程序执行路径的概率,以便某些编译器优化优先处理概率较高的路径。
    基于类型profile优化,即时编译器假设的是对象的动态类型仅为类型profile中的那几个。当假设失败的情况下,JVM给出的解决方案是“去优化”,从执行即时编译生成的机器码切换回解释执行。