方法内联是jvm jit编译器基于调用热度、字节码大小(高频325字节/普通35字节)和实现确定性(static/private/final或成功去虚化)综合决策的运行时优化,仅对热点方法开放,非满足即触发。

方法内联不是“一满足就立刻发生”的确定性行为,而是JVM在运行时综合调用热度、字节码大小、方法特征等多因素后做出的优化决策。它只对被JIT编译器识别为热点的方法开放,且必须满足体积与确定性双重门槛。
触发前提:必须是热点方法
只有被JIT判定为“执行频繁”的方法才进入内联候选队列:
- 未开启分层编译(-XX:-TieredStopAtLevel1)时,使用-XX:CompileThreshold参数控制:Client VM默认1500次,Server VM默认10000次
- 开启分层编译(默认启用)后,由-XX:Tier2InvocationThreshold、-XX:Tier3InvocationThreshold等多级阈值协同判断,更精细区分冷热路径
- 循环回边次数也参与统计——比如一个for循环执行1万次,等效于该方法被“逻辑调用”1万次,可能提前触发编译和内联
字节码体积限制:分场景双阈值
JVM对可内联方法的大小设了两道“门禁”,依据是否高频调用动态切换标准:
- 高频热点方法:允许最大325字节(64位平台常见,默认由-XX:FreqInlineSize控制),例如核心计算逻辑、循环体内反复调用的getter
- 普通非热点方法:仅允许最大35字节(默认由-XX:MaxInlineSize控制),典型如POJO的setter、空校验、单行委托等
- 字节码大小指编译后.class中该方法的
code属性长度,不是Java源码行数;可用javap -v查看
实现确定性:避免多态歧义
即使够小、够热,若JVM无法100%确认调用目标,仍不会内联:
-
安全类型:
static、private、final方法天然可内联(字节码指令为invokestatic/invokespecial) -
虚方法需去虚化:
public或protected实例方法(invokevirtual)只有在逃逸分析+类加载信息表明“当前类无子类重写”或“调用点唯一实现已知”时,才可能内联 - 接口方法极难内联:除非JVM通过类型推导确认只有一个具体实现类被加载(如模块封闭、sealed class场景)
验证与调试建议
想确认某方法是否被内联,可加以下JVM参数观察日志:
-
-XX:+PrintInlining:输出内联决策结果(成功/失败原因) -
-XX:+UnlockDiagnosticVMOptions -XX:+PrintAssembly(需hsdis):查看生成的汇编,确认调用指令是否消失 -
-XX:ReservedCodeCacheSize=256m:避免因CodeCache满导致内联退化(内联会显著增加生成代码量)










