文章目录

  • jvm架构理解
  • jvm程序执行流程
  • 执行流程图
  • 编译器和解释器的协调工作流程
  • 热点代码
  • 热点检测方式
  • 热点检测方式
  • 回边计数器

jvm架构理解

java 携带jvm_intellij-idea

jvm程序执行流程

执行流程图

  • Java编译成字节码、动态编译和解释为机器码的过程分析:

编译器和解释器的协调工作流程

java 携带jvm_maven_02

在部分商用虚拟机中(如HotSpot),Java程序最初是通过解释器(Interpreter)进行解释执行的,当虚拟机发现某个方法或代码块的运行特别频繁时,就会把这些代码认定为热点代码。为了提高热点代码的执行效率,在运行时,虚拟机将会把这些代码编译成与本地平台相关的机器码,并进行各种层次的优化,完成这个任务的编译器称为即时编译器(Just In Time Compiler,下文统称JIT编译器)。

由于Java虚拟机规范并没有具体的约束规则去限制即使编译器应该如何实现,所以这部分功能完全是与虚拟机具体实现相关的内容,如无特殊说明,我们提到的编译器、即时编译器都是指Hotspot虚拟机内的即时编译器,虚拟机也是特指HotSpot虚拟机。

我们的JIT是属于动态编译方式的,动态编译(dynamic compilation)指的是在运行时进行编译;与之相对的是事前编译(ahead-of-time compilation,简称AOT),也叫静态编译(staticcompilation)。

JIT编译(just-in-time compilation)狭义来说是当某段代码即将第一次被执行时进行编译,因而叫即时编译。JIT编译是动态编译的一种特例。JIT编译一词后来被泛化,时常与动态编译等价;但要注意广义与狭义的JIT编译所指的区别。

热点代码

程序中的代码只有是热点代码时,才会编译为本地代码,那么什么是热点代码呢?
运行过程中会被即时编译器编译的热点代码有两类:

  • 被多次调用的方法。
  • 被多次执行的循环体。

两种情况,编译器都是以整个方法作为编译对象。 这种编译方法因为编译发生在方法执行过程之中,因此形象的称之为栈上替换(On Stack Replacement,OSR),即方法栈帧还在栈上,方法就被替换
了。

热点检测方式

要知道方法或一段代码是不是热点代码,是不是需要触发即时编译,需要进行Hot Spot Dectection(热点检测)。
目前主要的热点探测方式有以下两种:

  • 基于采样的热点探测
    采用这种方法的虚拟机会周期性地检查各个线程的栈顶,如果发现某些方法经常出现在栈顶,那这个方法就热点方法。这种探测方法的好处是实现简单高效,还可以很容易地获取方法调用关系(将调用堆栈展开即可),缺点是很难精确地确认一个方法的热度,容易因为受到线程阻塞或别的外界因素的影响而扰乱热点探测。
  • 基于计数器的热点探测
    采用这种方法的虚拟机会为每个方法(甚至是代码块)建立计数器,统计方法的执行次数,如果执行次数超过一定的阀值,就认为它是热点方法。这种统计方法实现复杂一些,需要为每个方法建立并维护计数器,而且不能直接获取到方法的调用关系,但是它的统计结果相对更加精确严谨。

在HotSpot虚拟机中使用的是第二种——基于计数器的热点探测方法,因此它为每个方法准备了两个计数器:方法调用计数器和回边计数器。在确定虚拟机运行参数的前提下,这两个计数器都有一个确定的阈值,当计数器超过阈值溢出了,就会触发JIT编译。

热点检测方式

这个计数器用于统计方法被调用的次数。

  • 在JVM client模式下的阀值是1500次,Server是10 000次。可以通过虚拟机参数: -XX:
    CompileThreshold设置。但是JVM还存在热度衰减,时间段内调用方法的次数较少,计数器就减小。

回边计数器

它的作用就是统计一个方法中循环体代码执行的次数,在字节码中遇到控制流向后跳转的指令称为回边。

java 携带jvm_编译器_03