深入拆解Java虚拟机
郑雨迪
Oracle 高级研究员,计算机博士
立即订阅
27943 人已学习
课程目录
已完结 39 讲
0/4登录后,你可以任选4讲全文学习。
开篇词 (1讲)
开篇词 | 为什么我们要学习Java虚拟机?
免费
模块一:Java虚拟机基本原理 (12讲)
01 | Java代码是怎么运行的?
02 | Java的基本类型
03 | Java虚拟机是如何加载Java类的?
04 | JVM是如何执行方法调用的?(上)
05 | JVM是如何执行方法调用的?(下)
06 | JVM是如何处理异常的?
07 | JVM是如何实现反射的?
08 | JVM是怎么实现invokedynamic的?(上)
09 | JVM是怎么实现invokedynamic的?(下)
10 | Java对象的内存布局
11 | 垃圾回收(上)
12 | 垃圾回收(下)
模块二:高效编译 (12讲)
【工具篇】 常用工具介绍
13 | Java内存模型
14 | Java虚拟机是怎么实现synchronized的?
15 | Java语法糖与Java编译器
16 | 即时编译(上)
17 | 即时编译(下)
18 | 即时编译器的中间表达形式
19 | Java字节码(基础篇)
20 | 方法内联(上)
21 | 方法内联(下)
22 | HotSpot虚拟机的intrinsic
23 | 逃逸分析
模块三:代码优化 (10讲)
24 | 字段访问相关优化
25 | 循环优化
26 | 向量化
27 | 注解处理器
28 | 基准测试框架JMH(上)
29 | 基准测试框架JMH(下)
30 | Java虚拟机的监控及诊断工具(命令行篇)
31 | Java虚拟机的监控及诊断工具(GUI篇)
32 | JNI的运行机制
33 | Java Agent与字节码注入
模块四:黑科技 (3讲)
34 | Graal:用Java编译Java
35 | Truffle:语言实现框架
36 | SubstrateVM:AOT编译框架
尾声 (1讲)
尾声 | 道阻且长,努力加餐
深入拆解Java虚拟机
登录|注册

09 | JVM是怎么实现invokedynamic的?(下)

郑雨迪 2018-08-10
上回讲到,为了让所有的动物都能参加赛马,Java 7 引入了 invokedynamic 机制,允许调用任意类的“赛跑”方法。不过,我们并没有讲解 invokedynamic,而是深入地探讨了它所依赖的方法句柄。
今天,我便来正式地介绍 invokedynamic 指令,讲讲它是如何生成调用点,并且允许应用程序自己决定链接至哪一个方法中的。

invokedynamic 指令

invokedynamic 是 Java 7 引入的一条新指令,用以支持动态语言的方法调用。具体来说,它将调用点(CallSite)抽象成一个 Java 类,并且将原本由 Java 虚拟机控制的方法调用以及方法链接暴露给了应用程序。在运行过程中,每一条 invokedynamic 指令将捆绑一个调用点,并且会调用该调用点所链接的方法句柄。
在第一次执行 invokedynamic 指令时,Java 虚拟机会调用该指令所对应的启动方法(BootStrap Method),来生成前面提到的调用点,并且将之绑定至该 invokedynamic 指令中。在之后的运行过程中,Java 虚拟机则会直接调用绑定的调用点所链接的方法句柄。
在字节码中,启动方法是用方法句柄来指定的。这个方法句柄指向一个返回类型为调用点的静态方法。该方法必须接收三个固定的参数,分别为一个 Lookup 类实例,一个用来指代目标方法名字的字符串,以及该调用点能够链接的方法句柄的类型。
取消
完成
0/1000字
划线
笔记
复制
© 版权归极客邦科技所有,未经许可不得传播售卖。 页面已增加防盗追踪,如有侵权极客邦将依法追究其法律责任。
该试读文章来自付费专栏《深入拆解Java虚拟机》,如需阅读全部文章,
请订阅文章所属专栏。
立即订阅
登录 后留言

精选留言(13)

  • karl
    看了两遍 勉强有个概念了
    还是基础不够 看不懂啊

    作者回复: invokedynamic涉及到的东西很多,底层实现也在不断改进。看懂个大概就好啦

    2018-08-14
    7
  • ext4
    我知道Java对Lambda有个规定:“The variable used in Lambda should be final or effectively final",也就是说Lambda表达式捕获的变量必须是final或等同于final的。而文中您又讲到:“对于捕获了变量的Lambda,每次invokedynamic都需要新建适配器类实例,以防止他们发生变化”。JVM之所以这么做,是因为这种final的要求仅限于Java source层面,在bytecode层面是是无法保证的。我理解的对吗?

    作者回复: 语言里的final,是对于当前方法调用而言的。这是因为它实际上就传了个值进去。比如说你定义了int a,然后传入 i -> i +a里,那么之后你对a的修改lambda是看不到的。

    适配器针对的是多次不同调用,比如说每次调用你定义的final int a都不一样。

    2018-08-11
    6
  •  素丶  
    https://zhuanlan.zhihu.com/p/26389041
    https://zhuanlan.zhihu.com/p/30936412
    可以和 Shijie 大大的两篇文章配合着看。

    作者回复: 赞!

    2018-11-07
    5
  • code-artist
    一直没理解“逃逸分析”啥意思?

    作者回复: 逃逸分析是指通过数据流分析,判断一个对象会不会被传递到当前编译的方法之外。比如说你调用了一个方法,将一个新建的对象作为参数传递出去,如果这个方法没有被内联,则说明该新建对象会逃逸。

    逃逸分析是一项比较重要的优化,我后面会详细讲。

    2018-08-14
    5
  • 微笑
    如果该 Lambda 表达式捕获了其他变量,那么每次执行该 invokedynamic 指令,我们都要更新这些捕获了的变化。
    问题:捕获的变量必须是final,为什么还会变呢,为什么会线程不安全呢?
    2019-02-17
    3
  • 小鳄鱼
    老师,看来上一篇和这篇,又两个问题:
    1. 尽管逃逸分析能够去除这些额外的新建实例开销,但是它也不是时时奏效。那么什么情况下不奏效呢?
    2. 什么情况下编译器会将句柄识别成常量?除了本文中将MethodHandler定义为常量外,在其他什么情况下能识别为常量呢
    2018-11-15
    1
    2
  • Scott
    老师你好,我有两个问题,1是我看了几个有invokedynmaic指令的文件,都是invokedynamic #31, 0这种形式,似乎后面这个0没有什么作用,网上invokedynamic的解说也大多过时,我使用的是1.8.0_181版本。2. v10版本和v11版本性能的差距我猜想是v10版本不能正确的内联方法吧?虽然mh是final的,但是字节码层面已经丢失这个信息了。

    作者回复: 1. 这个数字0,指的是第几个bootstrap method,你多定义几个lambda,应该可以见到1 2 3等等。

    2. 对的,是不能内联。不过,字节码中字段处还是会有final标志的。C2认为final实例字段在编译过程中不应该被认为是不变的,因为应用程序可能通过Unsafe来更改。Graal认为可以当成不变的,毕竟Java语言规范没有规定不可以。

    V11的话,可以看出ConstantCallsite及时子类被特殊对待了。

    2018-08-19
    1
  • KW💤
    我想问下MonomorphicInlineCache这个例子,为什么能说“调用点方法句柄类型匹配”?
    "invoke"的methodType是MethodType.methodType(void.class, Object.class)
    “race”的methodType是 MethodType.methodType(void.class)。
    还有callsite的用处是什么,我感觉只是将MethodHandle包了一层返回而已,为什么要多这一层
    2019-07-09
  • 夕林语
    v10和v11的区别仅仅是v11的内部类继承了ConstantCallSite,ConstantCallSite是不可被更改链接的调用点,是不是说明v11的内部类被内联了?从而可以达到和直接调用近似的执行效率
    2019-04-17
  • 小橙橙
    其实有个地方一直没有想透,为什么要学习字节码,学习字节码对我们日常开发有什么作用吗,老师能否给指点迷津一下?

    作者回复: 主要是了解底层实现。

    对普通的日常开发可能作用不大。对于进阶的,比如分析应用的性能瓶颈,了解字节码将有所帮助。

    2018-08-19
  • Void_seT
    单态内联缓存的实现代码段,bootstrap方法的实现有问题,没有return一个CallSite类型返回值。另外,这篇有点难度了,看了三遍,勉强理解。

    作者回复: 多谢指出!

    2018-08-11
  • 小江
    老师邮箱可以提供一下吗,咨询一个问题,经过btrace增强后class文件错误问题
    2018-08-10
  • 自来也
    示例应该用jdk.internal.org.objectweb.asm.*包吧?
    2018-08-10
收起评论
13
返回
顶部