热点代码:
程序最初通过解释器进行解释执行的,当虚拟机发现某个方法或代码块的运行特别频繁时,就把这些代码认定为“热点代码”。
JIT编译器
把热点代码编译成与本地平台相关的机器码,并进行各层次的优化,完成这个任务的编译器称为即时编译器。也就是JIT编译器。
解释器与编译器并存
当程序需要迅速启动和执行时,解释器首先发挥作用,立即执行。随着时间推移,编译器把代码编译成本地代码之后,可以获取更高的执行效率。当内存资源限制较大时,使用解释器执行节约内存,反之可以使用编译器提升效率。
解释器预编译期搭配使用的方式在虚拟机称为“混合模式(Mixed Mode)”
-Xint:设置强制运行于“解释模式(Interpreted Mode)”,编译器不介入。
-Xcomp:设置强制运行于“编译模式”,优先采用编译方式执行,编译无法进行时,使用解释器。
运行模式
Client模式和Server模式。可以使用-client或-server参数设置。
分层编译:
第0层,程序解释执行,解释器不开启性能监控功能,可触发第一层编译
第1层,也称为C1编译,将字节码编译为本地代码,如有必有加入性能监控的逻辑。
第2层(或2层以上),也称为C2编译,将字节码编译为本地代码,但是会启用一些编译耗时较长的优化,甚至会根据性能监控信息进行一些不可靠的激进优化。
触发条件
热点代码被编译时,分为两种情况,当方法调用触发编译时,以整个方法作为编译对象,也是标准的JIT编译方式;当是循环体被多次调用时,尽管编译动作是由循环体触发,单编译器仍然会编译整个方法,由于发生在方法执行过程中,称之为栈上替换。
热点代码方法:
1.基于采样的热点探测:周期性检查各个线程的栈顶,如果发现某个方法经常出现在栈顶,那这个方法就是“热点方法”。
2.基于计数器的热点探测:为每个方法建立计数器,统计方法的执行次数,如果执行次数超过一定的阈值就认为是“热点方法”。
HotSpot如何探测热点代码?
HotSpot才有基于计数器的热点探测,为每个方法准备了方法调用计数器以及回边计数器。
方法调用计数器:
Client模式下默认阈值为1500,Server下为10000,可使用-XX:CompileThreshold设置。
当超过一定时间限度,方法的调用次数不足以交给即时编译器编译,方法的调用计数器就会减少一半,称为方法调用计数器的热度衰减,这段时间称为此方法统计的半衰周期。衰减的动作是在垃圾收集时进行的,可使用-XX:-UseConterDecay关闭热度衰减。可以使用-XX:CounterHalfLifeTime设置半衰周期时间,单位秒。
回边计数器:
统计一个方法中循环体代码执行的次数,在字节码中遇到控制流向后跳转的指令称为回边。
-XX:OnStackReplacePercentage:设置参数间接调整回边计数器阈值
Client-->方法调用计数器阈值✖️OSR 比率(OnStackReplacePercentage)/100。OnStackReplacePercentage默认是933
Server-->方法调用计数器阈值✖️(OSR比率(OnStackReplacePercentage)-解释器监控比率(InterpreterProfilePercentage))/100,InterpreterProfilePercentage默认为33,OnStackReplacePercentage默认是140
网友评论