JVM字节码指令

字节码指令

JVM字节码指令由一个字节长度,包含着特定含义的数值(操作码)以及跟随其后的零至多个操作所需参数(操作数)所构成;大多数字节码指令只有一个操作码,没有操作数,一般都是将操作所需参数存入操作数栈中;

字节码指令中有部分指令与数据类型相关联,比如iload/fload,将一个int/float类型的数据加载到操作数栈中;

字节码指令这块儿不算是虚拟机的重点,但是也有必要了解一些,下文会提到字节码指令的部分应用,以及部分指令;个人认为

把字节码指令之前的Class类文件学好比较重要,不过近些年的面试重点还是集中垃圾回收和类加载架构,大概再把前面的内容分

享之后会出一篇专门总结各种面试题的博客,希望大家有时间多多指正!

加载与存储指令

负责加载与存储:用于数据在操作数栈与局部变量表之间来回传输;

例子:将一个局部变量加载到操作数栈中 iload fload;

将一个数据从操作数栈中存储到局部变量表中 istore fstore;

还有一些比较零散的指令,比如访问对象的字段和数组元素的指令也可以向操作数栈中传输数据

回顾:操作数栈和局部变量表听起来很耳熟,这不是虚拟机栈的栈帧中的组件吗,又见面了 ,幸会幸会!

运算指令

用于将两个操作数栈的栈顶元素之间进行某种特定运算,并将计算结果重新压入到栈顶;

从整体来看分为两部分:针对于整数和浮点数的运算指令

加法指令:iadd ladd fadd dadd

减法指令:isub lsub fsub dsub 

目前来看不存在直接支持char short byte boolean类型的运算指令,和下文提到的返回指令非常相似,也是按照int类型来处理,综合来看这个指令以及前几个算是比较简单的,没啥东西

类型转换指令

用于两种不同类型的数据之间进行类型转换操作;可以为用户代码显示的进行类型转换;也可以用于虚拟机字节码指令集中与数据类型相关的指令无法与其数据类型相对应的问题

Java支持宽化类型的转换(即小范围类型向大范围类型的转换):

int类型可以转换为long float double类型

long 类型可以转换为float double类型

float 类型可以转换为double类型

解释下:曾经有一位很可爱的小朋友提到过,为什么没有反向宽化类型转换(或窄化类型转换);我觉得他非常幽默,把一个long类型的数据转换成int?不怕内存溢出吗?难道他只是想启动OOM,生成堆转储快照吗?果然一举双得啊,鼓掌!

操作数栈管理指令

将一个或两个操作数栈栈顶元素出栈:pop pop2

复制一个或两个操作数栈的栈顶元素并将复制值或双份复制值重新压入栈顶:dup dup2

将操作数栈栈顶的两个元素进行互换:swap

对象创建和访问指令

类实例与数组的创建与操作字节码指令有所区别,创建对象后,可以通过访问指令,获取对象实例,数组实例的字段,数组元素等;

创建一个类实例:new

创建一个数组:newarray

访问类字段(类变量,static)和实例字段(实例变量,非static):getstatic putstatic getfield putfield

方法调用和返回指令

调用对象的实例方法:invokeMethod

调用接口的方法:invokeinterface

调用指令与返回值没什么关系,但是返回指令与返回值却是一一对应的,比如ireturn(int char short byte boolean),dreturn,freturn,areturn,以及return指令用于void无返回值的方法,实力初始化方法,类和接口的类初始化方法;

以上指令基本上都可以做到见名知义,没有什么太大的难度,其实本来也比较简单

控制转移指令

该指令可以有条件或无条件的让虚拟机从当前执行位置的下一条指令的位置继续执行,从概念模型上来看,控制转移指令有条件或无条件的去修改PC寄存器的值(程序计数器)

这个PC寄存器会非常好心的提示线程当前应该执行哪个任务,之后干什么,以后干什么,就跟个FIFO的优先级列表似的,控制指令就跟个跳转指令似的;程序计数器属于JVM内存中的运行时数据区域这块会单独拿一章来盘

有条件分支:ifnull ifeq iflt ifgt

复合条件分支:tableswitch lookupswitch

无条件分支:goto jsr ret

异常指令

Java中显示的抛出异常(throw语句)由字节码athrow指令实现;

目前虚拟机中的异常处理由error_info实现,曾经JDK1.3时由jsr ret指令实现

同步指令

同步指令这块要分成两部分来讨论方法级的同步以及方法内一段指令序列集的同步,这两种同步结构都是由锁(monitor,也成管程)实现的

方法同步:

方法级的同步是隐式实现的,不需要字节码指令操作;方法同步会在方法调用与返回操作中实现的;虚拟机会检查方法常量池的方法表结构的访问标志ACC_SYNCHRONIZED是否设置为同步方法;

方法调用时,调用指令会检查访问标志ACC_SYNCHRONIZED是否设置,如果设置,由执行线程持有锁并执行方法,方法完成后释放锁(无论是正常完成还是非正常完成都要释放锁)

方法执行时,执行线程持有锁,其他线程不能在此时获取这个锁;

方法执行时,如果同步方法出现异常并且无法在方法内部处理时,执行线程所持有的锁会在异常抛出同步方法边界之外时自动释放;

指令序列集同步:

指令序列集同步由Java中synchronized关键字的语义支持,而支持synchronized关键字的语义由java中的两个指令集monitorenter/monitorexit实现;由javac编译器与jvm虚拟机共同支持!

个人观点:这块知识点可以注重学习同步指令和控制转移指令,可以说JVM这块没有重点却也全是重点,要是没有点儿勇气想学想背JVM还是比较吃力的,博主比较惨去年很菜的时候去了现在的公司,本来好好的研发部就跟个职能部门似的(可能还不如);没有产品/测试/前端,只能靠自己,一个人整理需求一个人写页面一个写后端代码一个人测试一个运维一个人挨怼;最关键的还是马云爸爸比较懂;写这篇文章的时候,博主已经学完了JVM的重点章节以及Redis;之后再学习Mysql和多线程;啃完这两块硬骨头,嘿嘿,你们懂得!

 

 

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值