JIT的全称是Just in time compilation,中文称之为即时编译,能够加速 Java 程序的执行速度。
在JVM刚启动的时候,java都是解释执行的,只有java程序运行足够时间后,jvm会挑选出来热点的方法和循环,将他编译成本地机器码。
JIT 的编译过程:
JIT是JVM最强大的武器之一,在运行时可以让java从屌丝到高富帅的飞跃,强大到很多人产生了java比C++快的幻觉,在google上搜索为什么java比c++快居然会有200W的结果。通常JIT的利用以下几种手段来优化JVM的性能
讨论JIT-方法内联的原理,以及如何在代码中实现方法内联。
要搞清楚为什么方法内联有用,首先要知道当一个函数被调用的时候发生了什么
这就是通常说的函数调用的压栈和出栈过程,因此,函数调用需要有一定的时间开销和空间开销,当一个方法体不大,但又频繁被调用时,这个时间和空间开销会相对变得很大,变得非常不划算,同时降低了程序的性能。根据二八原则,80%的性能消耗其实是发生在20%的代码上,对热点代码的针对性优化可以显著的提升系统的性能。
方法内联就是把被调用方函数代码"复制"到调用方函数中,来减少因函数调用开销的技术。
我们写一个简单的两数相加程序,被内联前的代码
private int add4(int x1, int x2, int x3, int x4) {
return add2(x1, x2) + add2(x3, x4);
}
private int add2(int x1, int x2) {
return x1 + x2;
}
运行一段时间后,代码被内联翻译成
private int add4(int x1, int x2, int x3, int x4) {
return x1 + x2 + x3 + x4;
}
JVM会自动的识别热点方法,并对它们使用方法内联优化。那么一段代码需要执行多少次才会触发JIT优化呢?通常这个值由-XX:CompileThreshold参数进行设置:
但是一个方法就算被JVM标注成为热点方法,JVM仍然不一定会对它做方法内联优化。其中有个比较常见的原因就是这个方法体太大了,分为两种情况。
我们可以通过增加这个大小,以便更多的方法可以进行内联;但是除非能够显著提升性能,否则不推荐修改这个参数。因为更大的方法体会导致代码内存占用更多,更少的热点方法会被缓存,最终的效果不一定好。
如果想要知道方法被内联的情况,可以使用下面的JVM参数来配置
-XX:+PrintCompilation //在控制台打印编译过程信息
-XX:+UnlockDiagnosticVMOptions //解锁对JVM进行诊断的选项参数。默认是关闭的,开启后支持一些特定参数对JVM进行诊断
-XX:+PrintInlining //将内联方法打印出来
虽然JIT号称可以针对代码全局的运行情况而优化,但是JIT对一个方法内联之后,还是可能因为方法被继承,导致需要类型检查而没有达到性能的效果
想要对热点的方法使用上内联的优化方法,最好尽量使用final、private、static这些修饰符修饰方法,避免方法因为继承,导致需要额外的类型检查,而出现效果不好情况。
针对热点方法,想要通过JIT内联优化来提升性能的建议
更小的方法体,JVM总是偏好更小的方法。
尽量使用final、private、static修饰符
使用+PrintInlining参数校验效果