一个JVM的指令包含了1个字节的操作码,该操作码用来表示要操作的动作,然后是0个或多个表示操作码的操作对象:参数或者其他数据。许多指令都没有操作数,而只有一个操作码。
不考虑异常的损耗,JVM解释器的内循环是很有效率的:
do{
atomically calculate pc and fetch opcode at pc;
If (operands) fetch operands;
execute the action for the opcode;
}while(there is more to do)
操作数的数量和大小由操作码决定。比如,如果一个16-bit大小的索引要存放在局域变量中,则要存放在2个字节中,记为byte1和byte2,所以这样存放的变量,其所表达的值为(byte1<<8)|byte2。
1.类型和JVM
大多数JVM中的指令集都要求它们要操作的动作所涉及的类型设定为一种。比如,iLoad指令表示从局部变量中加载的值必须是int类型的。同理,fload也要求加载的值的类型需要时float。这两个指令有相似的应用,但却有不同的操作数。
大多数带有类型要求的指令,指令的类型可以通过字母明显的看出。比如,i表示针对int的操作,l表示long,s表示short,b表示byte,c表示char,f表示float,d表示double,而a表示reference。而有些命令则没有表示类型的字母,比如arrayLength通常都是针对一个数组的操作。而一些类似goto的命令,则不操作带有类型信息的操作数。
从下面的表中,可以看出很多含有类型标注的指令。其中大多数的指中,byte,char和short都是空的。并且其中没有看到boolean的相关内容。怎么回事呢?在编译或运行时,编译器会将byte和short的值利用符号扩展变为int的值,然后再加以使用。而boolean和char的值则利用了0填充的方法将其值转换为int。
同样,从数组中加载boolean,short,byte,和char的值都被JVM在编译或运行期利用符号扩展或0扩展转变成了int类型的值。可以说,boolea,byte,char和short的操作与int的操作用的是一样的指令。
2. Load和Store指令
load和store指令是指操作数栈和局部变量区中的值的互相传递,局部变量区(local variables)和操作数栈(operand stack)都属于JVM帧(frame),这些指令包括:
• Load a local variable onto the operand stack:
iload, iload_<n>, lload, lload_<n>, fload, fload_<n>, dload, dload_<n>, aload, aload_<n>.
• Store a value from the operand stack into a local variable:
istore, istore_<n>,lstore, lstore_<n>, fstore, fstore_<n>, dstore, dstore_<n>, astore, astore_<n>.
• Load a constant onto the operand stack:
bipush, sipush, ldc, ldc_w, ldc2_w,aconst_null, iconst_m1, iconst_<i>, lconst_<l>, fconst_<f>, dconst_<d>.
• Gain access to more local variables using a wider index, or to a larger immediate operand:
wide.
3.算术指令
算术指令,一般都是从操作数栈中获得两个操作数,然后这两个数计算得到结果放回到操作数栈中。根据操作数的类型分,有两大类的算术指令,一是操作整数的指令;一是操作浮点类型的指令。没有直接操作byte,short,char或boolean类型的算术指令,它们都被视为int来进行操作。整数和浮点类型的操作指令的区别还体现在对“溢出”和“被0除”的行为上。算术指令包括:
• Add: iadd, ladd, fadd, dadd.
• Subtract: isub, lsub, fsub, dsub.
• Multiply: imul, lmul, fmul, dmul.
• Divide: idiv, ldiv, fdiv, ddiv.
• Remainder: irem, lrem, frem, drem.
• Negate: ineg, lneg, fneg, dneg.
• Shift: ishl, ishr, iushr, lshl, lshr, lushr.
• Bitwise OR: ior, lor.
• Bitwise AND: iand, land.
• Bitwise exclusive OR: ixor, lxor.
• Local variable increment: iinc.
• Comparison: dcmpg, dcmpl, fcmpg, fcmpl, lcmp.
JVM不会表示出整数类型的“溢出”。只有当除数为0的时候,针对int的操作才会抛出ArithmeticException,会跑出该异常的指令有:idiv, ldiv, irem,lrem; 针对浮点类型的指令遵循IEEE 754的标准。
4.转型指令
转换指令允许JVM的数字类型之间进行转型。
JVM支持一下几种向上转型:
•int to long, float, or double 指令为 i2l, i2f,i2d
•long to float or double 指令为l2f,l2d
•float to double 指令为f2d
其中,i2l, i2d, f2d这三个转型指令不会发生精度丢失的问题。而i2f, l2f, l2d 这三个转型指令可能会有精度丢失的问题,即它们回让最低有效位的一些值丢失.除去有可能的精度丢失,向上转型不会让JVM抛出Runtime Exception;
以及几种向下转型:
•int to byte, short, or char 指令为i2b,i2s,i2c
•long to int 指令为l2i
•float to int or long 指令为f2i,f2l
•double to int, long, or float 指令为d2i,d2l,d2f
显然,向下转型会引起精度丢失,有可能会让数字的正负号发生变化,有可能会让数量发生变化,或者两者都变化。一般来说向下转型要谨慎使用…很多bug都隐藏在向下转型中~
分享到:
相关推荐
JVM图解-JVM指令-JVM原型图.rar
深入理解Java代码执行过程--JVM 指令集
nginx-upstream-jvm-route 支持nginx版本1.15 解决nginx: [emerg] invalid parameter "srun_id=tomcat1" 问题
bcprov-ext-jdk15on-1.54.jar、bcprov-jdk15on-1.54.jar和ssl-provider-jvm16-0.2.jar附件下载
Moonbox(月光宝盒)是JVM-Sandbox生态下的,基于jvm-sandbox-repeater重新开发的一款流量回放平台产品。在jvm-sandbox-repeater基础上提供了更加丰富功能,同时便于线上部署和使用,更多对比参考。 使用场景 你...
java jvm 参数 -Xms -Xmx -Xmn -Xss -
赠送jar包:metrics-jvm-3.1.5.jar; 赠送原API文档:metrics-jvm-3.1.5-javadoc.jar; 赠送源代码:metrics-jvm-3.1.5-sources.jar; 赠送Maven依赖信息文件:metrics-jvm-3.1.5.pom; 包含翻译后的API文档:...
1、java虚拟机的基本介绍。 2、字节码的执行 3、常用的jvm参数配置 4、算法和种类 5、gc参数配置 6、类加载器 7、性能监控工具 8、jvm堆栈分析
此资源有两个文件,含 nginx-upstream-jvm-route 和 nginx 对应版本,都是tar.gz文件。 安装方法网上很多就不写了,亲测可用。 不用担心版本不匹配造成安装失败,再浪费积分去到处下载尝试的烦恼。 此资源有两个文件...
JVM基础-超清文字版.pdf 这个是带完整目录书签的文字版本,文本内容可以复制的哦
JVM规范--高手总结 Java相关 1 1.1Java定义 1 1.2Java的开发流程 1 1.3Java运行的原理 2 1.4半编译半解释 3 1.5平台无关性 4 JVM内存模型 4 2.1 JVM规范 5 2.2 Sun JVM 8 2.3 SUN JVM内存管理(优化) 10 2.4 SUN JVM...
赠送jar包:metrics-jvm-3.1.5.jar; 赠送原API文档:metrics-jvm-3.1.5-javadoc.jar; 赠送源代码:metrics-jvm-3.1.5-sources.jar; 赠送Maven依赖信息文件:metrics-jvm-3.1.5.pom; 包含翻译后的API文档:...
kotlinx-coroutines-io-jvm-0.1.1.jar
jvm-full-gc调优-jvm-full-gc
jvm调优-jvm
JVM指令集
jvm指令集
JVM实战-JVM类加载机制案例分析
JVM 的运行机制 多线程 JVM 的内存区域 JVM 会创建操作系统的接口创建一个原生线程。JVM 线程和操作系统线程是一一对应的