深入拆解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虚拟机
登录|注册

19 | Java字节码(基础篇)

郑雨迪 2018-09-03
在前面的篇章中,有不少同学反馈对 Java 字节码并不是特别熟悉。那么今天我便来系统性地介绍一遍 Java 字节码。

操作数栈

我们知道,Java 字节码是 Java 虚拟机所使用的指令集。因此,它与 Java 虚拟机基于栈的计算模型是密不可分的。
在解释执行过程中,每当为 Java 方法分配栈桢时,Java 虚拟机往往需要开辟一块额外的空间作为操作数栈,来存放计算的操作数以及返回结果。
具体来说便是:执行每一条指令之前,Java 虚拟机要求该指令的操作数已被压入操作数栈中。在执行指令时,Java 虚拟机会将该指令所需的操作数弹出,并且将指令的结果重新压入栈中。
以加法指令 iadd 为例。假设在执行该指令前,栈顶的两个元素分别为 int 值 1 和 int 值 2,那么 iadd 指令将弹出这两个 int,并将求得的和 int 值 3 压入栈中。
由于 iadd 指令只消耗栈顶的两个元素,因此,对于离栈顶距离为 2 的元素,即图中的问号,iadd 指令并不关心它是否存在,更加不会对其进行修改。
Java 字节码中有好几条指令是直接作用在操作数栈上的。最为常见的便是 dup: 复制栈顶元素,以及 pop:舍弃栈顶元素。
dup 指令常用于复制 new 指令所生成的未经初始化的引用。例如在下面这段代码的 foo 方法中,当执行 new 指令时,Java 虚拟机将指向一块已分配的、未初始化的内存的引用压入操作数栈中。
取消
完成
0/1000字
划线
笔记
复制
© 版权归极客邦科技所有,未经许可不得传播售卖。 页面已增加防盗追踪,如有侵权极客邦将依法追究其法律责任。
该试读文章来自付费专栏《深入拆解Java虚拟机》,如需阅读全部文章,
请订阅文章所属专栏。
立即订阅
登录 后留言

精选留言(14)

  • 东方
    详尽,赞👍

    随便找几断代码,javap反编译,查jvm手册一会儿就明白了
    2018-09-03
    17
  • godtrue
    1:.Java代码由Java的语言语法组成,有开发人员来编写

    2:.class 代码有Java编译器来编译,Java编译器也是有对应的开发人员来编写的,.class代码有字节码指令来组成,如果人理解Java字节码指令集比较简单也可以直接编写.class代码

    3:Java对应的机器码有JVM来编译出来,原料是.class代码,如果人类理解机器码比较容易,那么可能变成就直接在机器硬件上直接编写机器码了

    4:高级语言的出现是为提高人编写代码的效率,我们学习.class字节码指令集、JVM、机器码等的知识,是为了使我们编写高级语言代码能更好的在机器硬件上的执行效率更高,从高级语言的代码到能在机器上运行的机器码,中间经过了好几层的转换,所以,了解每一层是怎么转换就能更快的定位出高级语言代码的性能瓶颈了,感觉是为了在人的编码效率和机器的执行效率之间找平衡点

    有个疑问❓
    没太理解,JVM基于栈的计算模型的原因,推测可能是为了更简单的实现和更高的性能但是是怎么做到的呢?请老师解释一下

    作者回复: 基于栈的计算模型确实是为了实现起来容易一些,但它并不高效,因为没有使用底层体系架构的寄存器。

    在JVM中,只有解释器完整地模拟出该计算模型。即时编译器在解析字节码时会使用一个虚拟的栈计算模型,但是在接下来的编译优化,以及生成的机器码就不用了。

    2018-09-07
    6
  • 三木子
    为什么局部变量要初始化?想请老师专业解答下!

    作者回复: 如果是虚拟机初始化局部变量,那么它需要掌握每个变量的生命周期,以便初始化共享同一下标的局部变量。实现起来比较费事。

    另一方面,从代码规范来看,使用未经初始化的局部变量意义不明。

    2018-09-03
    3
  • code-artist
    “因此,我们需要利用 dup 指令复制一份 new 指令的结果,并用来调用构造器。当调用返回之后,操作数栈上仍有原本由 new 指令生成的引用去...”

    第一步栈顶压入new对象的引用r0,执行dup后复制r0得到r1,压入栈顶。r1用于调用构造器,完成后会pop, 留下栈顶元素r0。不知我这样理解对不?
    我的问题是为什么要dup呢?直接用r0不做pop不好吗?

    作者回复: 构造器是没有返回结果的,所以不用pop。如果不dup的话,就只有一个r0,在调用构造器时用掉了,程序就再没有对该新建对象的引用了。

    2018-09-06
    2
  • YIFENG
    64位虚拟机中long和double也都是占用两个栈单元吗?
    2018-09-03
    1
  • Void_seT
    数组访问指令表,int文稿中写的iaload,iastore;表格中列的iastore和istore

    作者回复: 多谢指出!

    2018-09-03
    1
  • gogo
    老师您好,从第一篇看到现在,对某个方法的执行流程还不是很理解,有哪一篇文章是说整个流程的吗,从主类加载初始化到某个方法执行结束的
    2019-09-29
  • 师爷
    某些方法阻塞会不会导致弹栈阻塞呢
    2019-09-25
  • 小美
    就是说如果是解释执行就在栈桢内完成了,不用寄存器。如果是即时编译执行,就用寄存器来存放操作数,对么
    2019-07-14
  • 沈飞龙
    想请教下 编译后匿名内部类会生成一个class文件,但是函数式接口实现的代码却不会生成一个class文件,这是什么原理?
    2019-04-22
  • ゞ﹏雨天____゛
    讲解内容中,这几张总结表,写的真的给力。赞
    2019-03-27
  • 李鑫磊
    笔记:https://www.jianshu.com/p/b395ed905e0d
    2018-11-19
  • 对方正在输入
    在JVM中,每个方法中,代码语句执行完毕,是不是都会默认有个return

    作者回复: 正常执行路径会有return,有返回值的是ireturn,areturn这些。异常执行路径会有athrow。你可以试试查看只有一句throw new Exception()的方法

    2018-11-12
  • 熊猫酒仙
    C/C++的汇编指令,会有大量寄存器的操作
    请问java的指令会用到寄存器吗?

    作者回复: Java字节码不会,但是底下的实现(比如解释执行器,即时编译器)是会的。

    2018-09-07
收起评论
14
返回
顶部