文章

Java编译器

Java编译器

编译器

编译器优化

运行时优化

主要是解释执行和动态编译通用的一些机制,如锁进制、内存分配机制 (如 TLAB)
还有专门用于优化解释执行效率的,如模板解释权、内联缓存(inline cache),用于优化虚方法调用的动态绑定

即时编译器 (JIT) 优化

JIT 优化是指将热点代码以方法为单位转化为机器码,直接运行在底层硬件之上。它采用了多种优化方式,包括静态编译器可以使用的如方法内联、逃逸分析;也包括基于程序的运行 profile 的投机性优化

方法内联

在编译的过程中遇到方法调用时,将目标方法的方法体取代原方法调用的优化手段。方法内联不仅可以消除调用本身带来的性能开销,还可以进一步触发更多的优化。
即时编译器不会无限制的进行方法内联,会根据方法的调用次数、方法体大小、code cache 的空间等去决定是否进行内联。(即使是热点代码,如果方法体过大,也不会进行内联,因为会占用更多内存空间)
尽可能使用小方法体;尽量使用 final、private 和 static 关键字修饰方法。

逃逸分析

判断一个对象是否被外部方法引用或外部线程访问的分析技术。JIT 可以根据逃逸分析的结果进行诸如锁消除、栈上分配以及标量替换等优化
锁消除
如果 JIT 能够证明锁对象不逃逸,那么对该锁对象的加锁、解锁操作没有任何意义,因为其他线程并不能获得该锁对象,在这种情况下,JIT 就可以消除对该对象的加锁、解锁操作。
栈上分配
JVM 中的对象都是在堆上进行分配的,而堆上的内容对任何线程可见;JVM 需要对所分配的堆内存进行管理,并且在对象不再被引用时回收其所占据的内存。如果逃逸分析能证明某些新建的对象不会逃逸,那么 JVM 完全可以将其分配到栈上,并且在方法退出时,通过弹出当前方法栈帧来自动回收所分配的内存空间。
标量替换
由于实现栈上分配实现起来需要更改大量假设了 “ 对象只能堆分配 “ 的代码,HotSpot VM 并没有采用栈上分配,而是使用了标量替换这技术。所谓的标量,就是仅能存储一个值的变量,比如 Java 代码中的局部变量。标量替换这些优化技术,可以看成将原本对对象的字段的访问,替换成一个个的局部变量的访问。

本文由作者按照 CC BY 4.0 进行授权