网页设计与制作教程第五版答案,郴州seo服务,建设网站时间,网站添加flash【0】README0.1#xff09;本文全文转自 “深入理解jvm”#xff0c; 旨在了解 java字节码指令 的基础知识#xff1b;【1】写在前面1#xff09;由于jvm 采用面向操作数栈而不是寄存器的结构#xff0c;所以大多数的指针都不包含操作数#xff0c;只有一个操作码#x…【0】README0.1本文全文转自 “深入理解jvm” 旨在了解 java字节码指令 的基础知识【1】写在前面1由于jvm 采用面向操作数栈而不是寄存器的结构所以大多数的指针都不包含操作数只有一个操作码2由于限制了jvm操作码的长度为一个字节0~255这意味着指令集的操作码总数不可能操作256个【2】字节码与数据类型1下表列举了jvm 所支持的与数据类型相关的字节码指令通过使用数据类型列所代表的特殊字符替换opcode列的指令模板中的T就可以得到一个具体的字节码指令。如果在表中指令模板与数据类型两列共同确定的格为空则说明虚拟机不支持对这种数据类型【3】加载和存储指令1作用用于将数据在栈帧中的局部变量表和操作数栈之间来回传输这类指令包括如下内容1.1将一个局部变量加载到操作数栈iload, iload_n, lload, lload_n, fload, fload_n, dload, dload_n, aload, aload_n1.2将一个数值从操作数栈存储到局部变量表istore, istore_n, lstore_, lstore_n, fstore fstore_n, dstore_, dstore_n, astore, astore_n1.3将一个常量加载到操作数栈 bipush, sipush, ldc, ldc_w, ldc2_w aconst_null, iconst_m1, iconst_i, lconst_l, fconst_f, dconst_d1.4扩充局部变量表的访问索引的指令wide 2存储数据的操作数栈和局部变量表主要就是由加载和存储指令进行操作【4】运算指令1作用运算指令用于对两个操作数栈上的值进行某种特定运算并把结果重新存入到操作栈顶2算术指令汇总如下2.1加法指令iadd, ladd, fadd, dadd;2.2减法指令isub, lsub, fsub, dsub; 2.3乘法指令imul, lmul, fmul, dmul;2.4除法指令idiv, ldiv, fdiv, ddiv; 2.5求余指令irem, lrem, frem, drem;2.6取反指令ineg, lneg, fneg, dneg;2.7位移指令ishl, ishr, iushr, lshl, lshr, lushr; 2.8按位或指令ior, lor;2.9按位与指令iand, land; 2.10按位异或指令ixor, lxor2.11局部变量自增指令iinc;2.12比较指令dcmpg, dcmpl, fcmpg, fcmpl, lcmp; 3向最接近数舍入模式 jvm 要求在进行浮点数计算时 所有的运算结果都必须舍入到适当的精度非精确结果必须舍入为可被表示的最接近的精确值如果有两种可表示的形式与该值一样接近将优先选择最低有效位为零的4向零舍入模式将浮点数转换为整数时采用该模式 该模式将在目标数值类型中选择一个最接近但是不大于原值的数字作为最精确的舍入结果5NaN值当一个操作产生溢出时将会使用有符号的无穷大表示如果某个操作结果没有明确的数学定义的话将会使用 NaN值来表示而且所有使用NaN值作为操作数的算术操作结果都会返回 NaN干货——这里提到了NaN值【5】类型转换指令1宽化类型转换jvm 支持以下数值类型的宽化类型转换即小范围类型向大范围类型的安全转换1.1int到long float或double1.2long到float或double1.3float到double 2窄化类型转换转换过程仅仅是丢弃除最低位N个字节外的内容 N是类型T 的数据类型长度这将可能导致转换结果与输入值有不同的正负号3将一个浮点值转换为int类型时遵循如下的转换规则rulesr1如果浮点值是NaN 那转换结果是int 或 long类型的0r2如果浮点值不是无穷大的话浮点值使用 向零舍入模式取整获得整数值v且v在目标类型Tint或double的表示范围内r3否则根据v的符号转换为T所能表示的最大或最小整数 【6】对象创建和访问指令1对象创建后就可以通过对象访问指令获取对象实例或数组实例中的字段或者数组元素这些指令instruction如下i1创建类实例的指令newi2创建数组的指令newarray, anewarray, multianewarray;i3访问类字段static字段或称为类变量和实例字段的指令 getfield, putfield, getstatic, putstatic;i4把一个数组元素加载到操作数栈的指令 baload, caload, saload, iaload, laload, faload, daload, aaload;i5将一个操作数栈的值存储到数组元素中的指令 bastore, castore, sastore, iastore, fastore, dastore, aastore;i6取数组长度指令 arrayLength;i7检查类实例类型的指令 instanceof checkcast 【7】操作数栈管理指令1如同操作一个普通数据结构中的堆栈那样jvm提供了一些用于直接操作操作数栈的指令包括1.1将一个或两个元素出栈 poppop21.2复制栈顶一个或两个数值并将复制值或双份的复制值重新压入栈顶dup, dup2, dup_x1, dup2_x1, dup_x2, dup2_x21.3将栈最顶端的两个数值交换 swap 【8】控制转移指令1条件分支ifeq, iflt, ifle, ifne, ifgt, ifge, ifnull, ifnonnull, if_icmpeq, if_icmpne, if_icmplt, if_icmpgt, if_icmple, if_icmpge, if_acmpeq, if_acmpne;2复合条件分支tableswitch, lookupswitch;3无条件分支goto, goto_w, jsr, jsr_w, ret;【9】方法调用和返回指令1方法调用指令1.1invokevirtual用于调用对象的实例方法 根据对象的实际类型进行分派虚方法分派这也是java中最常见的方法分派方式1.2invokeinterface用于调用接口方法 它会在运行时搜索一个实现了这个接口方法的对象找出合适的方法进行调用1.3invokespecial用于调用一些需要特殊处理的实例方法 包括实例初始化方法私有方法和父类方法1.4invokestatic用于调用类方法static方法1.5invokedynamic用于在运行时动态解析出调用点限定符所引用的方法并执行该方法前面4条调用指令的分派逻辑都固化在 java 虚拟机内部而 invokedynamic指令的分派逻辑是由用户所设定的引导方法决定的 2返回指令根据返回值的类型区分的包括2.1ireturn, lreturn, freturn, dreturn, areturn另外还有一条return 指令供声明为 void 的方法实例初始化方法以及类和接口的类初始化方法使用 【10】异常处理指令1athrow指令【11】同步指令1java虚拟机支持两种同步结构方法级的同步和 方法内部一段指令序列的同步这两种同步都是使用管程monitor来支持的2方法级的同步是隐式的 即无须通过字节码指令来控制它实现在方法调用和返回操作之中。虚拟机可以从方法常量池的方法表结构中的 ACC_SYNCHRONIZED 访问标志得知一个方法是否声明为同步方法3synchronized语句块同步一段指令集序列通常是由java 中的synchronized语句块来表示的jvm的指令集有 monitorenter 和 monitorexit 两条指令来支持 synchronized关键字的语义4看个荔枝// 测试 synchronized关键字的虚拟机指令集字节码指令
public class SynchronizedTest {public void func(CandyMachine machine) {synchronized (machine) {machine.count;}}class CandyMachine {private int count 0;public int getCount() {return count;}}
}对以上代码的分析Analysis编译器必须确保无论方法通过何种方式完成方法中调用过的每条 monitorenter指令都必须执行其对应的 monitorexit指令而无论这个方法是正常ending 还是 异常ending【12】公有设计和私有实现1jvm 规范描述了jvm 应有的共同程序存储格式 Class 文件格式以及字节码指令集2虚拟机实现的方式有两种typetype1将输入的java虚拟机代码在加载或执行时翻译成另一种虚拟机的指令集type2将输入的java虚拟机代码在加载或执行时翻译成宿主机CPU 的本地指令集 即JIT代码生成技术jitjust in time 即时