一、方法内联
方法内联指的是在即时编译过程中遇到方法调用时,直接编译目标方法的方法体,并替换原方法调用。
注:
- 方法内联属于即时编译期的优化技术;
- 即时编译的过程是字节码被解析成IR图,优化IR图,再由优化过的IR图生成机器码的过程;
- 解析指的是即时编译器对字节码做的动作,是字节码到IR图的转换;
二、方法内联要点
内联也可以表述成2个IR图的融合,在该过程中,有一些要点值得注意。
- 目标IR图的接收参数节点要和调用者IR图的传参节点相连;
- 所有指向调用者IR图调用节点的边要重新指向目标IR图返回值节点,如果目标IR图有多个返回值节点,则生成一个聚合节点;
- 目标IR图抛异常的路径要和调用者IR图的异常处理路径相连;
- 融合后的IR图还有优化的空间;
三、方法内联的规则
内联越多,生成代码的效率越高,编译时间越长,峰值性能的到达时间越晚;内联越多,机器码越长,当超过阈值(-XX:ReservedCodeCacheSize),即时编译将关闭。触发和不触发方法内联遵从一定的规则。
触发方法内联的规则
- 自动拆箱总被内联;
- -XX:CompileCommand中的inline指令指定的方法;
- @ForceInline注解的方法;
不触发方法内联的规则
- Throwable类的方法不能被其他类中的方法内联;
- -XX:CompileCommand中dotinline或exclude指令指定的方法;
- @Dontinline注解的方法;
- 调用字节码对应的符号引用未被解析;
- 目标方法所在的类未被初始化;
- 目标方法是native方法;
- C2不支持内联超过9层的调用(-XX:MaxInlineLevel),以及1层的直接递归调用(-XX:MaxRecursIninleLevel)
其他影响是否方法内联的因素
- 方法调用指令所在程序的热度;
- 目标方法的调用次数及大小;
- 当前IR图的大小;
总结
即时编译器中的内联算法更青睐于小的方法。