invokedynamic 是 Java 7 引入的一条新的虚拟机指令,它是自 JVM 1.0 以来第一次引入新的虚拟机指令。这条指令在 Java 8 中开始被广泛应用,尤其是在 Lambda 表达式的实现中。invokedynamic 与其他 invoke 指令的主要区别在于它允许由应用级的代码来决定方法解析,这通过一个被称为引导方法(Bootstrap Method,简称 BSM)的机制来实现。

当 JVM 执行到 invokedynamic 指令时,它会调用与该指令关联的引导方法。引导方法负责在运行时动态生成和链接要调用的方法,并返回一个称为“调用站点”(CallSite)的对象。这个对象封装了目标方法的所有信息,包括方法句柄、参数类型和返回类型等。一旦调用站点对象被创建并返回给 invokedynamic 指令,JVM 就会将该指令与调用站点对象关联起来。在后续的执行过程中,当再次遇到相同的 invokedynamic 指令时,JVM 会直接通过调用站点对象调用目标方法,而无需再次执行引导方法,这种机制可以显著提高动态方法调用的性能。

jvm
jvm

在 Java 8 中,Lambda 表达式的实现就依赖于 invokedynamic 指令。编译器会为 Lambda 表达式生成一个 invokedynamic 指令,该指令的引导方法会负责生成实现了函数式接口的类,并将其实例化。这个实例化的对象就是 Lambda 表达式的运行时表示,它可以被传递给其他方法或存储在变量中。当 Lambda 表达式被调用时,实际上是调用了这个动态生成的对象的相应方法。

invokedynamic 指令的性能优化包括热点探测和即时编译(JIT),调用站点对象的缓存和重用,以及内联优化等操作。这些优化措施进一步提高了动态方法调用的性能。对于无状态的 Lambda 表达式,其性能与直接调用没有差别,因为它们在第一次调用时动态生成适配类后,后续调用都会通过缓存的调用站点对象直接调用目标方法。然而,对于捕获外部变量(闭包)的 Lambda 表达式,每次调用都可能需要创建新的适配类实例,这可能会带来额外的性能开销。

总的来说,invokedynamic 指令是 JVM 中一项非常重要的特性,它为 Java 语言带来了更强大的动态能力,使得 Java 能够更好地支持动态类型语言和脚本语言在 JVM 上的实现。同时,invokedynamic 指令也为 Java 语言的未来发展提供了更多的可能性。