深入拆解 Java 虚拟机
郑雨迪
Oracle 高级研究员,计算机博士
87446 人已学习
新⼈⾸单¥59
登录后,你可以任选4讲全文学习
课程目录
已完结/共 40 讲
模块四:黑科技 (3讲)
深入拆解 Java 虚拟机
15
15
1.0x
00:00/00:00
登录|注册

05 | JVM是如何执行方法调用的?(下)

超多态内联缓存
多态内联缓存
单态内联缓存
索引值
实现方式
内联缓存
方法表
性能差距观测
方法内联
内联缓存的作用
动态绑定
静态绑定
invokeinterface指令
invokevirtual指令
性能优化
虚方法调用
JVM方法调用

该思维导图由 AI 生成,仅供参考

我在读博士的时候,最怕的事情就是被问有没有新的 Idea。有一次我被老板问急了,就随口说了一个。
这个 Idea 究竟是什么呢,我们知道,设计模式大量使用了虚方法来实现多态。但是虚方法的性能效率并不高,所以我就说,是否能够在此基础上写篇文章,评估每一种设计模式因为虚方法调用而造成的性能开销,并且在文章中强烈谴责一下?
当时呢,我老板教的是一门高级程序设计的课,其中有好几节课刚好在讲设计模式的各种好处。所以,我说完这个 Idea,就看到老板的神色略有不悦了,脸上写满了“小郑啊,你这是舍本逐末啊”,于是,我就连忙挽尊,说我是开玩笑的。
在这里呢,我犯的错误其实有两个。第一,我不应该因为虚方法的性能效率,而放弃良好的设计。第二,通常来说,Java 虚拟机中虚方法调用的性能开销并不大,有些时候甚至可以完全消除。第一个错误是原则上的,这里就不展开了。至于第二个错误,我们今天便来聊一聊 Java 虚拟机中虚方法调用的具体实现。
首先,我们来看一个模拟出国边检的小例子。
abstract class Passenger {
abstract void passThroughImmigration();
@Override
public String toString() { ... }
}
class ForeignerPassenger extends Passenger {
@Override
void passThroughImmigration() { /* 进外国人通道 */ }
}
class ChinesePassenger extends Passenger {
@Override
void passThroughImmigration() { /* 进中国人通道 */ }
void visitDutyFreeShops() { /* 逛免税店 */ }
}
Passenger passenger = ...
passenger.passThroughImmigration();
这里我定义了一个抽象类,叫做 Passenger,这个类中有一个名为 passThroughImmigration 的抽象方法,以及重写自 Object 类的 toString 方法。
确认放弃笔记?
放弃后所记笔记将不保留。
新功能上线,你的历史笔记已初始化为私密笔记,是否一键批量公开?
批量公开的笔记不会为你同步至部落
公开
同步至部落
取消
完成
0/2000
荧光笔
直线
曲线
笔记
复制
AI
  • 深入了解
  • 翻译
    • 英语
    • 中文简体
    • 中文繁体
    • 法语
    • 德语
    • 日语
    • 韩语
    • 俄语
    • 西班牙语
    • 阿拉伯语
  • 解释
  • 总结

本文深入探讨了Java虚拟机(JVM)中虚方法调用的执行过程,以及优化手段内联缓存的实现原理。通过模拟出国边检的例子引入主题,详细介绍了虚方法调用和方法表的实现原理。在动态绑定的过程中,Java虚拟机通过方法表快速定位目标方法,实现了高效的虚方法调用。文章还提到了内联缓存和方法内联等优化手段,以及单态、多态和超多态内联缓存的实现方式。内联缓存能够缓存虚方法调用中调用者的动态类型,以及该类型所对应的目标方法,从而加速动态绑定。此外,文章还介绍了内联缓存的性能差距和实践环节,展示了单态内联缓存和超多态内联缓存的性能对比。通过深入浅出的讲解,读者可以快速了解JVM中虚方法调用的具体实现及其对性能的影响,以及内联缓存的优化原理和实践应用。

仅可试看部分内容,如需阅读全部内容,请付费购买文章所属专栏
《深入拆解 Java 虚拟机》
新⼈⾸单¥59
立即购买
登录 后留言

全部留言(92)

  • 最新
  • 精选
  • 啊一大狗
    置顶
    这套课很好,谢谢!
    2018-07-31
    26
  • Tony
    同提建议,代码使用英文。刚学java基础时,有老师为了便于理解用中文命名。现在都来学jvm,对java很熟悉了,看到中文不仅不会觉得通俗易懂,反而特别别扭。

    作者回复: 多谢建议! 原本是英文的,录音的时候觉得老要切换,就给换了。。

    2018-07-30
    69
  • C_love
    提个小建议,能否在代码中都使用英文?毕竟使用中文作对象名不值得提倡

    作者回复: 谢谢建议!

    2018-07-30
    25
  • 老师问一个概念性的问题: 虚方法 到底在指什么样的 方法? 也就是什么样的方法,才叫做虚方法?

    作者回复: 可以被子类覆盖的方法。例如,某段程序调用父类的方法A.foo(),由于调用者(receiver)是子类B的实例,实际执行的是子类的同名同参数方法B.foo()。那么A.foo就是一个虚方法,因为你不知道会调到哪里去 这是面向对象编程的一个重要概念,用来实现多态的

    2019-12-22
    2
    18
  • 左岸🌸开
    为什么调用超类非私有实例方法会属于静态绑定呢?

    作者回复: 通过super关键字来调用父类方法,本意就是想要调用父类的特定方法,而不是根据具体类型决定目标方法。

    2018-07-30
    8
    17
  • MARK
    没用过中文写代码,居然认为中文会编译错误T﹏T 老师是为了课件方便这样写,自己写作业就改下呗,又没规定要每个字照抄 [root@localhost cqq]# javac Passenger.java [root@localhost cqq]# java Passenger cost time : 1167 cost time : 3156 [root@localhost cqq]# java -XX:CompileCommand='dontinline,*.exit' Passenger CompilerOracle: dontinline *.exit cost time : 3709 cost time : 7557

    作者回复: 哈,我以前也认为无法编译,直到有一次我看到一个俄语的方法名。。 另外,如果你用javap -v查看常量池的话,你会发现类名方法名以及方法描述符都是用UTF8来存的。

    2018-07-30
    10
  • 吾是锋子
    郑老师,您好。有个具体的问题想请教下,String类里面indexOf(String str)调用的是自己类里面indexOf(String str, int fromIndex)方法,但我自己在测试的时候却发现两个方法的速度有很明显的差异,看字节码也没有发现什么特殊。 不知道是不是我忽略了什么,希望您能抽空点拨下,感谢!

    作者回复: HotSpot里有String.indexOf intrinsic,用了很多向量化指令,所以性能会快很多的。 关于intrinsic的概念,你可以理解为HotSpot识别指定方法后,将其替代为语意等价的高效实现。

    2018-08-14
    2
    9
  • 方枪枪
    一直不能明确一个问题,执行哪个方法,是不是都是在运行的时候确定的,如果是的话,coding的时候,写一个不存在的方法or传入不存在的参数,编译会报错,那这个合法性的检测,是一个什么逻辑?另外关于方法的确定,对于Java来说,是按照传入的形参确定执行哪个重写的方法,对于 groovy 是按照实际类型确定执行哪个方法,这两个区别在JVM层面是如何实现的?

    作者回复: 合法性检测是根据编译器能找到的class文件来判定的。你可以在编译后,移除掉相应的class文件或者库文件,就会出现你所说的不存在的方法的情况了。 第二个问题,在各自的编译器中已经作出区分了。在Java字节码中就只是根据类名,方法名和方法描述符来定位方法的。

    2018-08-01
    7
  • 万花
    代码用汉语也挺好的呀。来这都是学jvm的,没有来学编码规范的吧……

    作者回复: 哈,多谢支持。不过汉语编程有个问题,没办法区分大小写,因此变量名和类名容易混淆

    2018-07-30
    2
    3
  • vimfun
    老师,打印耗时的System.out.println 用的太多了吧?

    作者回复: 你是指课后作业吗? 打印语句每一亿次循环只会运行一次,相对来说并不耗时。

    2018-07-30
    2
收起评论
显示
设置
留言
92
收藏
沉浸
阅读
分享
手机端
快捷键
回顶部