JVM:晚期(运行期)优化的深入理解

  

<强>晚期(运行期)优化

  

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

  

本章提到的编译器,即时编译器都是指热点虚拟机内的即时编译器,虚拟机也是特质热点虚拟机

  

<强> 1,热点虚拟机内的即时编译器

  

1),解释器与编译器

  

当程序需要迅速启动和执行的时候,解释器可以首先发挥作用,省去编译的时间,立即执行。在程序运行后,随着时间的推移,编译器逐渐发挥作用,把越来越多的代码编辑成本地代码之后,可以获取更高的执行效率。当程序运行环境中内存资源限制较大,可以使用解释执行节约内存,反之可以使用编译执行来提升效率

  

 JVM:晚期(运行期)优化的深入理解

  

热点虚拟机中内置了两个即时编译器,分别称为客户机编译器和服务器编译器,或者简称为C1编译器和C2编译器。目前主流的热点虚拟机中,默认采用解释器与其中一个编译器直接配合的方式工作,程序使用哪个编译器,取决于虚拟机运行的模式,热点虚拟机会根据自身版本与宿主机器的硬件性能自动选择运行模式。用户也可以使用“客户”或“- Server”参数去强制指定虚拟机运行在客户端模式或服务器模式

  

解释器与编译器搭配使用的方式在虚拟机中称为“混合模式”,用户可以使用参数“-Xint”强制虚拟机运行于解释模式,这时编译器完全不介入工作,全部代码都使用解释方式执行。另外,也可以使用参数“-Xcomp”强制虚拟机运行于编译模式,这时将优先采用编译方式执行程序,但是解释器仍然要在编译无法进行的情况下介入执行过程,可以通过虚拟机的“- version”命令的输出结果显示出这3中模式

        C:\Users\ hxt> java - version   java版本“1.8.0_162”   Java (TM) SE运行时环境(构建1.8.0_162-b12)   Java HotSpot VM (TM) 64位服务器(构建25.162 b12,混合模式)   ----------------------------------------------------------------------   C:\Users\ hxt> java -Xint - version   java版本“1.8.0_162”   Java (TM) SE运行时环境(构建1.8.0_162-b12)   Java HotSpot VM (TM) 64位服务器(构建25.162 b12,解释模式)   ----------------------------------------------------------------------   C:\Users\ hxt> java -Xcomp - version   java版本“1.8.0_162”   Java (TM) SE运行时环境(构建1.8.0_162-b12)   Java HotSpot VM (TM) 64位服务器(构建25.162 b12,编译模式)      

为了在程序启动响应速度与运行效率之间达到最佳平衡,热点虚拟机会启用分层编译的策略,分层编译根据编译器编译,优化的规模与耗时,划分出不同的编译层次,其中包括:

  
      <李>第0层,程序解释执行,解释器不开启性能监控功能,可触发第1层编译   <李>第1层,也称为C1编译,将字节码编译为本地代码,进行简单,可靠的优化,如有必要将加入性能监控的逻辑李   <李>第2层,也称为C2编译,也是将字节码编译为本地代码,但是会启用一些编译耗时较长的优化,甚至会根据性能监控信息进行一些不可靠的激进优化李   
  

用C1编译器获取更高的编译速度,用C2编译器获取更高的编译质量,在解释执行的时候也无须再承担收集性能监控信息的任务

  

2),编译对象与触发条件

  

在运行过程中会被即时编译器编译的热点代码有两类:

  
      <李>被多次调用的方法   <李>被多次执行的循环体李   
  

对于第一种情况,由于是由方法调用触发的编译,因此编译器会以整个方法作为编译对象,这种编译也是虚拟机标准的JIT编译方式。而对于后一种情况,尽管编译动作是由循环体所触发的,但编译器依然会以整个方法作为编译对象。这种编译方式因为编译发生在方法执行过程之中,因此称之为栈上替换(OSR编译,即方法帧还在栈上,方法就被替换了)

  

判断一段代码是不是热点代码,是不是需要触发即时编译,这样的行为称为热点探测,其实进行热点探测并不一定要知道方法具体被调用了多少次,目前主要的热点探测判定方式有两种:

JVM:晚期(运行期)优化的深入理解