什么是JIT?怎么优化?
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
什么是JIT?怎么优化?
什么是JIT
JIT 是 just in time 的缩写, 也就是即时编译编译器。
在运⾏时 JIT 会把翻译过的机器码保存起来,以备下次使⽤,因此从理论上来说,采⽤该 JIT 技术可以接近以前纯编译技术。下⾯我们看看,JIT 的⼯作过程。
备注:寄存器的使⽤是编译器的⼀个⾮常普遍的优化。寄存器的速度⽐主存快很多。
怎么优化JIT编译
初级调优:客户模式或服务器模式
中级编译器调优(-cient,-server 或是-xx:+TieredCompilation)
优化代码缓存 (–XX:ReservedCodeCacheSize)
编译阈值 (-XX:CompileThreshold)
检查编译过程 (XX:+PrintCompilation)
⾼级编译器调优
编译线程 (-XX:CICompilerCount)
从优化的⾓度讲,最简单的选择就是使⽤ server 编译器的分层编译技术,这将解决⼤约 90%左右的与编译器直接相关的性能问题。最后,请保证代码缓存的⼤⼩设置的⾜够⼤,这样编译器将会提供最⾼的编译性能。
HotSpot中的JIT编译器
1.1 编译器和解释器
HotSpot中有编译器和解释器并存。
HotSpot中内置两个JIT编译器:
JVM根据⾃⾝版本和机器硬件性能⾃动选择
Client Compiler,简称C1,-client参数强制
Server Compiler,简称C2, -server参数强制
解释器和编译器搭配使⽤成为混合模式(Mixed Mode)
⽤-Xint参数强制JVM运⾏与解释模式,全部⽤解释⽅式,编译器不介⼊
⽤-Xcomp强制JVM运⾏于编译模式,优先采⽤编译⽅式
分层编译:根据⽐那⼀起编译,优化的规模耗时,划分出不同的编译层次
第0层,程序解释执⾏,解释器不开启性能监测功能,触发第⼀层编译
第1层,也叫C1编译,将字节码编译为本地代码,进⾏简单,可靠的优化,如有必要,加⼊性能监测的逻辑
第2层(或者2层以上),也叫C2编译,将字节码⽐那⼀位本地代码,但会开启⼀些编译耗时较长的优化,甚⾄根据性能监控信息进⾏⼀些不可靠的激进优化
分层编译后,Client Compiler和Server Compiler将会同时⼯作,代码可能会被多次编译,⽤Client获得更⾼的编译速度,⽤Server获得更好的编译质量,解释执⾏的时候⽆需搜集性能监控信息
1.2 编译对象和触发条件
热点代码有两类:
多次调⽤的⽅法
多次执⾏的循环体,实际上也会以整个⽅法作为编译对象
判断热点的⽅法主要有两种:
基于采样的热点探测(Sample Based Hot Spot Detection):周期性检查各个线程的栈顶,发现某个(某些)⽅法经常出现在栈顶,就是热点⽅法
有点简单⾼效,可以获取⽅法调⽤关系(将调⽤堆栈展开即可)
缺点是很难精确确认⽅法热度,容易受到线程阻塞等外界因素影响
基于计数器的热点探测(Counter Based Hot Spot Detection):为每个⽅法(甚⾄代码块)建⽴计数器,统计⽅法调⽤次数,如果执⾏超过阈值就认为是热点⽅法。缺点是实现较为困难。优点是结果更精确。
基于计数器的探测:
Client模式下默认1500次,Server下默认10000次,根据参数-XX:CompileThreshold设定。
调⽤⼀个⽅法,先检查是否存在JIT编译版本本地代码,存在优先使⽤本地代码,不存在将计数器加1。然后判断调⽤计数器和回边计数器之和是否⼤于阈值,如果超过,⽤JIT编译器提交编译请求。JIT编译完成后⽅法调⽤⼊⼝就被系统换成新的。下次调⽤已编译版本。
计数器热度衰减(Counter Decay超过⼀定的时间限度,⽅法的调⽤次数仍未达到阈值,⽅法计数器减少⼀半。在垃圾收集期间执⾏,⽤-UseCounterDecay来关闭,以统计绝对次数。⽤-XX:CounterHalfLifeTime设置半半衰周期。
回边计数器:统计⽅法中⽅法体代码执⾏的次数,在字节码中遇到控制流向后跳动的指令成为回边(Back Edge)。
回边计数器阈值可以⽤-XX:OnStackReplacePercentage来间接调整。
回边计数器没有热度衰减过程。
1.3 编译过程
JVM默认情况下对于即时编译请求在编译完成之前,都按照解释⽅式执⾏,编译动作在后台线程执⾏
参数-XX:-BackgroundCompilation禁⽌后台编译,此时编译请求会等待,直到编译完成后直接执⾏本地代码
Client Compiler:关注局部优化,简单快速,放弃耗时的长时优化
Server Compiler:⾯向服务端,⾼性能,复杂,较缓慢
本⽂由猿必过发布