java 虚拟机 字节码_深入理解Java虚拟机:字节码执行引擎

一、运行时栈帧结构

10096573798d6c99b34190b70a2b0fd0.png

栈帧:用于支持虚拟机进行方法调用和方法执行的数据结构,也是虚拟机运行时数据区中的虚拟机栈的栈元素。栈帧存储了方法的局部变量表、操作数栈、动态链接、方法返回地址。在活动线程中,只有位于栈顶的方法才是运行的,只有位于栈顶的栈帧才是有效的。1)局部变量表

一组变量值的存储空间,用于存放方法参数和方法内部定义的局部变量。变量槽(Slot)为最小单位boolean、byte、char、short、int、float、reference、returnAddress分别占用一个变量槽。long、double分别占用两个变量槽。当一个方法被调用时,Java虚拟机会使用局部变量表来完成参数值到参数变量列表的传递过程,即实参到形参的传递。当执行的是非static修饰的方法时,布局变量表中第0位索引的变量槽默认为传递方法所属对象实例的应用。为了节省栈帧耗用的内存空间,局部变量表中的变量槽是可以重用的。2)操作数栈

一个后进先出的栈。当一个方法刚刚开始执行的时候,这个方法的操作数栈是空的,在方法执行过程中,会有各种字节码指令向操作数栈中写入和读取内容,即出栈入栈操作。优化处理:令两个栈帧出现一部分重叠;节约空间、在记性方法调用时可以直接公用一部分数据,无须进行额外的参数赋值传递了。

d4cc6bac5c942e9c75976d027c2d7c3d.png

3)动态链接

每个栈帧都包含一个指向运行时常量池中该栈帧所属方法的引用,持有这个引用是为了支持方法调用过程中的动态链接4)方法返回地址

当一个方法开始执行后,只有两种方式能退出该方法。正常调用完成:执行引擎遇到任意一个方法返回的字节码指令。异常调用完成:在方法执行的过程中遇到了异常,并且没有catch或throw的异常。

二、方法调用

1)解析

调用不同类型方法的指令invokestatic:调用静态方法。invokespecial:调用实例构造器()方法、私有方法和父类的方法。invokevirtual:调用所有的虚方法。invokeinterface:调用接口方法。invokedynamic:运行时动态解析出调用点限定符引用的方法,在执行该方法。方法调用方式:静态(在编译期间就完全确定,在类加载的解析阶段就会把符号引用转变为直接引用);分派2)分派

静态分派所有依赖静态类型来决定方法执行版本的分派动作。典型应用表现:方法重载动态分派典型应用表现:方法重写单分派与多分派虚拟机动态分派的实现invokevirtual运行时解析过程找到操作栈顶的第一个元素所指向的对象实际类型C。如果在类型C中找到与常量中的描述符和简单名称都相符的方法,则进行访问权限检验,如果通过则返回这个方法的直接引用,查找过程结束。不通过则返回java.lang.IllegalAccessError异常。否则,按照继承关系从下往上依次堆C的各个父类进行第二步的搜索和验证过程。如果始终没有找到合适的方法,则抛出java.lang.AbstractMethodError异常。三、基于栈的字节码解释执行引擎

b49d379e8ea07bdad23cfc2be6342541.png

1)基于栈的指令集与基于寄存器的指令集

基于栈的指令集:Javac编译器输出的字节码指令流,字节码指令流里面的指令大部分都是零地址指令,它们依赖操作数栈进行工作。举例说明:iconst_1

iconst_1

iadd

istore_0

基于寄存器的指令集:主流PC机中物理硬件直接支持的指令集架构,依赖寄存器进行工作。举例说明:mov eax, 1

add eax, 1

特点:基于栈的指令集可移植,基于寄存器的指令集由硬件控制,受到硬件的约束;基于栈的指令集代码相对更加紧凑(字节码中每个字节就对应一条指令,而多地址指令集中还需要存放参数),但是完成相同功能所需的指令数量也会多。编译器实现更加简单(不需要考虑空间分配的问题,所需空间都在栈上操作)基于栈的指令集执行速度相对慢基于栈的指令集实现在内存中,频繁的内存访问,是执行速度的瓶颈2)基于栈的解释器执行过程

7712e2c250138aade291a0192aa01e3c.png

4ff981458e2e3f6a71ccd90cbb4b68f8.png

1.执行偏移地址为0的指令,bipush指令的作用是将单字节的整形常量值(-128~127)推入操作数栈顶,跟随一个参数,指明推送的常量值100。

3c22ba1169b1d2ba1fb6ea51da89a6e2.png

2.执行偏移地址为2的指令,istore_1指令的作用是将操作数栈顶的整型值出栈并存放在第1个局部变量槽中。同理,偏移量地址为3,4,7,10的指令操作。

80f223e32c89d77f6fbe42bc783dece0.png

3.执行偏移地址为11的指令,iload_1指令的作用是将局部变量表第1个变量槽中的整形值复制到操作数栈顶。

320159490a9eb2dd6fca9129dc29b634.png

4.执行偏移地址为12的指令,iload_2指令的执行过程与iload_1类似,把第2个变量槽的整型值入栈。

5929af5ecfe31d8be5a7bce51a556dbf.png

5.执行偏移地址为13的指令,iadd指令的作用是将操作数栈中头两个栈顶元素出栈,做整形假发,然后把结果重新入栈。在iadd指令执行完毕后,栈中原有的100和200被出栈,它们的和300被重新入栈。

dd6034abd8c67e3604e4cd04ded0c152.png

6.执行偏移地址为14的指令,iload_3指令把存放在第3个局部变量槽中的300入栈到操作数栈中。这时操作数栈为两个整数300,。下一条指令imul是将操作数栈中头两个栈顶元素出栈,做整形乘法,然后把结果重新入栈,与iadd一样。

da5d0d3c807085d4f555f6ea480f4b49.png

7.执行偏移地址为16的指令,ireturn指令是方法返回指令之一,它将结束方法执行并将操作数栈顶的整型值返回给该方法的调用者。

d544f128aef5e78c31834a5cb4ea9292.png

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值