vlambda博客
学习文章列表

java虚拟机——即时编译器和解释器

java虚拟机讲解第八篇

1、讲解内容逻辑梳理图:

逻辑图为百度脑图,以下为原图连接:http://naotu.baidu.com/file/17c1cd2e634918a57df6a0ec9d983317?token=7743a63b2c17f937

2、内容详细讲解:

2.1、即时编译器:程序在运行过程中虚拟机将“热点代码”编译成本地代码,提高后续的执行效率。触发条件:被多次调用的方法和被多次执行的循环体。

2.1.1、基于采样的热点探测优点:实现简单、高效,缺点:很难精准的确认一个方法的热度,容易受到线程阻塞和外界因素影响。

2.1.2、基于计数器的热点探测:为每个方法建立计数器,Hotspot采用此方法。

a)、方法调用计数器:当方法调用超过阀值(client模式为1500次、server模式为10000次)就会触发JIT编译。当一段时间内计数器值不足以提交给即时编译器,则在垃圾回收时进行计数器减半操作,此过程为计数器热度的衰减。

b)、回边计数器:统计方法体中循环代码执行的次数,没有热度衰减的过程。


2.2、即时编译器的优化技术:

a)、语言无关的经典优化技术之一:公共子表达式消除。

b)、语言相关的经典优化技术之一:数组范围查找消除。

c)、重重要的优化技术之一:方法内联。

d)、最前沿的优化技术之一:逃逸分析。

2.2.1、公共子表达式消除:如果一个表达式E已经计算过了,并且从先前的计算到现在E中所有的变量值没有发生过变化,那么E的这次出现就成为了公共子表达式。

2.2.2、数组范围查找消除:如果数组的下表为数字(foo[3]),在编译期根据数据流分析确定foo.length的值,并且判断出3小于该长度,则执行期可消除判断。循环中访问数组,如根据数据流分析确定循环变量的取值范围在[0,foo.length]区间,则执行期间可消除数组上下界的检查。

2.2.3、方法内联:一可以消除方法调用的成本,二为其他的优化手段建立基础。方法内联即将目标方法体的执行代码复制到调用方的方法中,编译器在进行内联时,如果为虚方法(私有方法、实例构造器、父类方法、invokestatic指令调用的静态方法)可直接进行内联,如果为非虚方法,则需要通过CHA(类型继承关系分析)来确定方法有多个实现版本,如果只有一个则可进行内联,该内联方式属于激进优化,会预留逃生门。后续如发现有多个实现版本方法,则抛弃已编译的代码,退回到解释执行,或进行重新编译。

2.2.4、逃逸分析:分析对象的动态作用域,如一个对象在方法中定义后,通过调用参数传递到其他方法中,则为方法逃逸。通过赋值给类变量或在其他线程中访问的实例变量,则为线程逃逸。

当确定一个对象不会逃逸到方法或线程之外时,可进行一些高效优化:

a)、栈上分配:当确定对象不会逃逸时,可将对象分配到栈空间内,对象所占用的内存空间会随着栈帧出栈而销毁,减小垃圾收集的压力。

b)、同步消除:当逃逸分析确定一个变量不会被多个线程同时访问时,对这个变量实施的同步就可以消除掉。

c)、标量替换:标量为无法在分解为更小的数据来表示,如基本类型及reference。数据可以继续分解的为聚合量,如对象。将Java对象拆散,根据程序的访问,将使用到的成员变量恢复为基本类型来访问即为标量替换。


往期回顾:

8)、java虚拟机——即时编译器和解释器(图文方式讲解即时编译器和解释器的工作内容)

9)、java虚拟机——内存模型和线程(图文方式讲解内存模型和线程内容)

10)、java虚拟机——线程安全与锁优化(图文方式讲解线程安全及锁优化内容)