方法内联
方法内联
方法内联指的是在编译过程中遇到方法调用时,将目标方法的方法体纳入编译范围之中,并取代原方法调用的优化手段。它不仅可以消除调用本身带来的性能开销,还可以进一步触发更多的优化。
举个例子,如果没有方法内联,当调用getter/setter方法时,程序需要保存当前方法的执行位置,创建并压入用于getter/setter的栈帧,访问字段,弹出栈帧,最后再恢复当前方法的执行,当内联了对getter/setter的方法调用后,上述操作仅剩字段访问。
即时编译器首先解析字节码,并生成IR图,然后在该IR图上进行优化,优化是由一个个独立的优化阶段串联起来的,每个优化阶段都会对IR图进行转换,最后即时编译器根据IR图的节点以及调度顺序生成机器码。
一个相对于IR图好理解的内联形式:
1 | public int add(int a, int b , int c, int d){ |
内联之后
1 | public int add(int a, int b , int c, int d){ |
不难发现,内敛后少了两次方法的调用,那么就意味着少了两次的方法的入栈。
内联的条件
- 热点代码。如果一个方法的执行频率很高就表示优化的潜在价值就越大。这里是根据编译器的编译模式来决定的,如果是客户端模式,则次数是1500,服务端编译模式是10000,该大小可以通过
-XX:CompileThreshold来调整
。 - 方法体不能太大。jvm中被内联的方法会编译成机器码放在code cache中。如果方法体太大,则能缓存热点方法就少,反而会影响性能。
- 由 -XX:CompileCommand 中的 inline 指令指定的方法,以及由 @ForceInline 注 解的方法(仅限于 JDK 内部方法),会被强制内联。
- 如果调用字节码对应的符号引用未被解析、目标方法所在的类未被初始化,或者目标方 法是 native 方法,都将导致方法调用无法内联。