运行期优化
JAVA最初是通过解释器进行解释执行的,当虚拟机发现某个方法或代码块的运行特别频繁,就会把这些代码认定为“热点代码”而将它们编译成本地机器码
?
HOTSPOT和J9都是解释器和编译器并存,保留解释器的原因是,加快启动时间,立即执行,当运行环境中内存资源限制较大时,解释器可以节约内存,解释器还可以作为激进优化的编译器的“逃生门”(称为逆优化Deoptimization)
?
HOTSPOT内置了两个即时编译器,client compiler和server compiler,称为C1,C2,默认是采用解释器与其中一个编译器直接配合的方式工作。HOTSPOT会根据自身版本和宿主机器的性能自动选择运行模式,用户也可以使用-client或-server来决。
?
这种解释器编译器搭配的方式成为混合模式,用户还可以使用-Xint强制虚拟机使用“解释模式”
也可以使用-Xcomp强制“编译模式”
?
被编译的触发条件:
- 被多次调用的方法被多次执行的循环体(栈上替换)OSR On Stack Replacement
- 基于采样的热点探测,JVM会周期性检查各个线程的栈顶,如果某个方法经常出现在栈顶,那就认定为热点方法。简单高效,精度不够。基于计数器的热点探测,统计方法执行次数。(HOTSPOT使用这种方式)
方法调用计数器并不是统计方法调用绝对次数,而是一个相对执行频率,超过一定时间,如果方法调用次数不足以让它提交给编译器,则计数器就会被减少一半,这种现象称为热度衰减(Counter Decay),进行热度衰减的动作是在垃圾回收时顺便进行的,而这段时间就被称为半衰周期(Counter Half Life Time)可用-XX:-UseCounterDecay来关闭热度衰减,用-XX:CounterHalfLifeTime来设置半衰时间。
回边计数器用于统计方法中循环体的执行次数。字节码遇到控制流向后跳转 的指令成为回边。回边的控制参数有-XX:BackEdgeThreshold,-XX:OnStackReplacePercentage.
编译是后台进行的,可以通过-XX:-BackgroundCompilation来禁止后台编译