JVM复习(晚期优化)
JVM复习(晚期优化)
文章目录
一,晚期(运行期)优化
1.三种编译器
- 前端编译器:直接把.java文件转变成.class文件
- 后端运行期编译器(JIT):把字节码转变成机器码
- 静态提前编译器(AOT):直接把.java文件编译成本地机器码
2.编译器和解释器
2.1编译器
编译器是将字节码编译为机器码,并存入code cache,下次遇到相同的代码直接执行,无需重复编译(根据平台类型 生成特定的机器码)
2.2解释器
解释器是将字节码解释为针对所有平台都适用的机器码,下次遇到相同的字节码仍会执行重复的解释
2.3联系
所以,当程序需要迅速启动和执行的时候,解释器可以首先发挥作用,省去编译时间,立即执行;程序运行之后,随着时间的推移,编译器逐渐发挥作用,把越来越多的代码编译成本地代码之后,可以获取更高的执行效率,当程序运行环境中内存资源限制较大时,可以使用解释执行节约内存,反之可以使用编译执行来提升效率
3.编译对象和触发条件
在运行过程中会被即时编译器编译的是热点代码:
- 被多次执行的方法
- 被多次执行的循环体
如何判断是否是热点代码
- 基于采样的热点探测
- 基于计数器的热点探测
3.1基于采样的热点探测
采用这种方法的虚拟机会周期性的检查各个线程的栈顶,如果发现某个方法经常出现在栈顶,那这个方法就是热点方法,基于采样的热点探测的好处就是实现简单,高效,还可以很容易的获取方法调用关系,缺点就是很难精确的确认一个方法的热度,容易因为受到线程阻塞或者别的外界因素的影响而扰乱热点探测
3.2基于计数器的热点探测
采用这种方法虚拟机会为每个方法建立计数器,统计方法的执行次数,如果执行次数超过一定阀值就认为他是热点方法
1.方法调用计数器
方法调用计数器统计方法被调用的次数
2.回边计数器
统计一个方法中循环体代码执行的次数,在字节码中遇到向后跳转的指令称为回边
4.编译优化技术
方法内联
方法内联的主要目的;
- 去除方法调用的成本(建立栈桢)
- 为其他优化建立良好的基础,方法内联膨胀后,可以便于在更大范围上采用后续的优化手段,从而获取更好的优化效果
公共字表达式清除
如果一个表达式E已经计算过了,并且从先前的计算到现在E中所有变量的值都没有发生变化,那么E的这次出现就成为了公共子表达式。对于这种表达式,没有必要花时间再对它进行计算,只需要直接用前面计算过的表达式结果代替E就可以了
逃逸分析
逃逸分析的基本行为就是分析对象动态作用域:当一个对象在方法中被定义后,他可能被外部方法所引用,例如作为调用参数传递到其他方法中,称为方法逃逸。甚至还有可能被外部线程访问到,譬如赋值给类变量或可以在其他线程中访问的实例变量,称为线程逃逸
如果能证明一个对象不会逃逸到方法或线程之外,也就是别的方法或线程无法通过任何途径访问到这个对象,则可能为这个变量进行一些高效的优化
-
栈上分配
如果确定一个对象不会逃逸出方法之外,那让这个对象在栈上分配内存,对象分配的内存空间可以随栈桢出栈而销毁
-
同步消除
线程同步本身是一个相对耗时的过程,如果逃逸分析确定一个变量不会逃逸出线程,无法被其他线程访问,那这个变量的肯定没有读写竞争,对于这个变量可是实施同步消除
-
标量替换
如果逃逸分析证明一个对象不会被外部访问,并且这个对象可以被拆散的话,那程序真正执行的时候将可能不创建这个对象,而改为直接创建他的若干个被这个方法使用的成员变量来代替