Day350.字节码指令集与解析举例 -JVM
Posted 阿昌喜欢吃黄桃
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Day350.字节码指令集与解析举例 -JVM相关的知识,希望对你有一定的参考价值。
字节码指令集与解析举例
一、概述
1、执行模型
jvm虚拟机的执行模型流程,根据pc寄存器在记录接下来要执行的位置,来自旋的执行判断操作码与操作数
2、字节码与数据类型
操作码指令会携带操作的数据类型
3、指令分析
二、加载与存储指令
使用频率最高,加载:往操作数栈中操作,存储:存储在局部变量表中
1、复习:再谈操作数栈与局部变量表
i/s是槽位共用,因为int i = 0出了代码块,就失效了,所以下面的String s变量就不开辟新的槽位,直接复用上面的i
2、局部变量压栈指令
Xload操作:从局部变量表中的指定索引位置的变量,压入操作数栈中
3、常量入栈指令
const、push、ldc:将常量压入操作数栈
对应的常量表示数值的范围依次变大
4、出栈入局部变量表指令
里面有代码,也有字节码,所以可以根据老师给的图展开分析,首先该方法被调用的时候,形式参数k和d都是有确定的值,由于该方法不是静态方法,所以局部变量表中的第一个位置(槽位)存储this,而第二个位置存储k具体的值,由于老师只是分析,没有调用这个方法,所以老师全部使用的变量名称来代替具体的值,所以明白就好,继续来分析,然后第三个和第四个位置储存d具体的值,由于d是double类型,所以需要占据两个槽位,数据已经准备好了,那就来看字节码,首先iload_1是将局部变量表中下标为1的k值取出来压入操作数栈中,然后iconst_2是将常量池中的整型值2压入操作数栈,iadd让操作数栈弹出的k值和整型值2执行相加操作,之后将相加的结果值m压入操作数栈中,请注意老师的画法,在执行弹栈和压栈操作之后,老师并没有删除操作数栈中的k值和2,这是因为老师让我们知道具体的操作过程,所以故意为之,不过真正的操作是弹栈之后k值和2就会从操作数栈中弹出,之后操作数栈中就没有k值和2了,只有m值了,然后istore_4是将操作数栈中的m值弹出栈,然后存在局部变量表中下标为4的位置,idc2_w #13代表将long型值12压入操作数栈,istore5是将值12弹栈之后放入局部变量表中下标为5的位置,由于12是long型,所以占据两个位置(槽位),ldc #15代表将字符串atguigu压入操作数栈,astore 7代表将字符串atguigu弹栈之后放入局部变量表中下标为7的位置,idc #16代表将float类型数据10.0压入操作数栈,fstore 8代表将10.0弹出栈,然后放入局部变量表中下标为8的位置,idc2_w #17代表将10.0压入操作数栈,dstore2代表将10.0弹出栈,之后将10.0放入下标为2和3的操作,毕竟这是double类型数据
槽位复用:
注意:在方法没有运行的时候,根据字节码文件就可以计算出需要几个槽位
三、算数指令
对于无穷大和NaN的举例:
1、所有算术指令
①举例
②一个曾经的案例1
2、比较指令的说明
注意:NaN(Not a Number)表示不是一个数字,比如0.0/0.0得到的可能是1.0(两个数相等),也可能是0.0(0.0是分子),也可能是无穷大(0.0是分母),所以老师给出的解释是NaN代表无法确定是什么数字,只有double和float类型中可能出现NaN的情况,而long类型不会出现NaN,所以只有lcmp,而没有lcml
3、i++和++i的区别
- 对于
i++
,先赋值后++
先加载10到操作数栈【bipush 10】,并保存到局部变量表1索引的位置(0的位置是this)【istore_1】,然后自增局部变量表索引1的变量【iinc 1 by 1】,(此时10还在操作数栈中),然后把操作数栈中当前的10,存储在索引2中【istore_2】,最终的结果是i=11(索引1的位置),a=10(索引2的位置);总结i=11,a=10;
- 对于
++i
,先++后赋值
先是加载20到操作数栈中【bipush 20】,将操作数栈20的数据保存到索引3的位置【istore_3】,自增索引3位置的数据【iinc 3 by 1】,此时索引3的数据是21,加载索引3的数据到操作数栈中【iload_3】,然后存储到索引为4的位置,此时索引为3的数据为21,索引为4的数据也是21,;总结j=21,b=21;
对于++i和i++,对于i都会自增,但是对于他所赋值给的对象,会有不同的时机进行自增;
四、类型转换指令
明天继续!!!
以上是关于Day350.字节码指令集与解析举例 -JVM的主要内容,如果未能解决你的问题,请参考以下文章