java虚拟机基础知识(八):晚期(运行期)优化
即时编译器(JIT编译器):运行时,虚拟机将会把热点大吗编译成与本地平台相关的机器码,并进行各种层次的优化
一、Hotspot虚拟机内的即时编译器
1)解释器与编译器共存的架构:当程序需要迅速启动和执行的时候,解释器可以首先发挥作用,省去编译的时间,立即执行;在程序运行后,编译器把越来越多的代码编译成本地代码,可以获取更高的执行效率;内存资源限制较大—使用解释执行节约内存,反之用编译执行提升效率
2)Hotspot虚拟机中内置了两个即时编译器,分别称为client complier 和server complier,简称c1编译器和c2编译器(opto编译器)
3)混合模式:解释器与编译器搭配使用的方式
解释模式:使用参数“-xint”强制用解释方式
编译模式:使用参数“-xcomp”强制用编译方式
二、 编译对象与触发条件
热点代码:被多次调用的方法—jit编译方式
被多次执行的循环体—栈上替换(osr编译)
热点探测:判断一段代码是否为热点代码,方式如下:
1)基于采样的热点探测:虚拟机周期性的检查各个线程的栈顶,若某个(些)方法经常出现在栈顶,则为“热点方法”
优点:简单高效,容易获取方法调用关系
缺点:精确度低,易受线程阻塞或其他外界因素影响
2)基于计数器的热点探测:虚拟机为每个方法(甚至是代码块)建立计数器,统计方法执行次数,若超过一定的阈值则为“热点方法”
【Hotspot有方法调用计数器和回边计数器】
优点:精确度高
缺点:麻烦
----方法调用计数器:默认阈值在client模式下是1500次,在server模 式下是10000次,可用-XX:compliethreshold来人为设定(过程如图)
----回边计数器:作用是统计一个方法中循环体代码执行的次数,在字节码中遇到控制流向后跳转的指令称为“回边”。使用-XX:OnStackReplacePercentage来间接调整阈值。【Client模式:方法调用计数器阈值*osr比率(默认933)/100,都取默认值,则回边阈值等于13995;Server模式:方法调用计数器阈值*(osr比率(默认140)-解 释器监控比率(默认值33)/100)都取默认值,则回边阈值等于10700】
三、 编译优化技术
1、公共子表达式消除
含义:如果一个表达式E已经计算过了,并且从先前的计算到现在e中所有变量的值都没有发生变化,那么e的这次出现就 成为了公共子表达式
例:int d =(c*b)*12+a+(a+b*c);Javac编译器不会进行任何优化,但在即时编译器中,检测到”b*c”和“c*b”一样的表达式, 则int d =E*12+a+(a+E);甚至(代数化简)优化为:int d =E*13+a*2;
2、数组边界检查消除
为了安全,数组边界检查时必须做的,但对于拥有大量数组访问的代码,性能负担较大。常见使用场景:数组访问发生在循环中,并且使用循环变量来进行数组访问,如果编译器只要通过数据流分析就可以判定循环变量的取值范围永远在区间[0,**.length-1]内,那在整个循环中就可以吧数组的上下界检查消除以节省很多次的条件判断操作
3、方法内联
4、逃逸分析:是为其他优化手段提供依据的分析技术,基本行为是分析对象动态作用域。若能证明一个对象不会逃逸到方法或线程外,则可进行以下优化:使用参数-XX:+DoEscapeAnalysis手动开启
使用参数-XX:+PrintEscapeAnalysis来查看分析结果
- 栈上分配:对象可随方法的结束自动销毁,垃圾收集系统压力会小很多
- 同步消除:由于逃逸分析可确定变量不会逃逸出线程,则该变量的读写肯定不会有竞争。使用-XX:+EliminateLocks开启
- 标量替换:标量是指一个数据已经无法再分解成更小的数据表示,如果把一个java对象拆散,根据程序访问情况,将其用到的成员变量恢复原始类型来访问就叫做标量替换。
使用参数:-XX:+EliminateAllocations开启标量替换
使用参数:-XX:+PrintEliminateAllocations查看替换结果