Java字节码

什么是字节码:

  Java的使命是一次编译,处处运行。在不同的操作系统、不同的硬件平台上,均可以不用修改代码即可顺畅地执行。

  之所以能一次编译,处处运行,有以下原因:

    1)把编译的过程分成两部分,首先无论在什么平台它会先由javac编译成通用的固定的中间形式——字节码(.class文件),然后再由解释器逐条将字节码解释为机器码来执行。

    2)JVM针对各种操作系统、平台都进行了定制

  

  Java所有的指令有200个左右,一个字节(8位)可以存储256种不同的指令信息,一个这样的字节称为字节码(bytecode)。

  在代码的执行中,JVM将字节码解释执行,屏蔽对底层操作系统的依赖;JVM也可以将字节码编译执行,如果是热点代码,会通过JIT动态地编译为机器码,提高执行效率。

如何将源代码转化为字节码:

  我们编写好的 .java 文件是源代码文件,并不能交给机器直接执行,需要将其编译为字节码甚至是机器码文件。

  静态编译器将源码转化为字节码的过程:

字节码的执行:

  字节码必须通过类加载过程加载到JVM环境后,才可以执行。

  执行有三种模式:

    ①:解释执行

    ②:JIT(Just In Time,即时编译器)编译执行

    ③:JIT编译与解释混合执行(主流JVM默认执行模式)

      混合执行模式的优势在于解释器在启动时先解释执行,省去编译时间。随着时间推进,JVM通过热点代码统计分析,识别高频的方法调用、循环体、公共模块等,基于强大的JIT动态编译技术,将热点代码转换为机器码,直接交给CPU执行。

      JIT的作用是将Java字节码动态地编译成可以直接发送给处理器指令执行的机器码。

字节码主要指令:

  1、加载或存储指令

    在某个栈帧中,通过指令操作数据在虚拟机栈的局部变量表与操作栈之间来回传输,常见指令如下:

    (1):将局部变量加载到操作栈中

      ILOAD:将int类型的局部变量压入栈

      ALOAD:将对象引用的局部变量压入栈

    (2):从操作栈顶存储到局部变量表

      ISTORE、ASTORE

    (3):将常量加载到操作栈顶,这是极为高频使用的指令      

      ICONST:加载 -1 ~-5 之间的数

      BIPUSH:Byte Immediate PUSH,加载 -128~127之间的数

      SIPUSH:Short Immediate PUSH,加载 -2^15~-2^15-1之间的数

      LDC:Load Constant,在-2^31~-2^31-1之间的数 或者 是字符串时,JVM采用LDC指令压入栈中

  2、运算指令

    对两个操作栈帧上的值进行运算,并把结果写入操作栈顶,如IADD、IMUL等

  3、类型转换指令

    显示转换两种不同的数值类型,如I2L、D2F等

  4、对象创建与访问指令

    根据类进行对象的创建、初始化、方法调用相关指令,常见指令如下:

    (1):创建对象指令,如NEW、NEWARRAY等

    (2):访问属性指令,如GETFIELD、PUTFIELD、GETSTATIC等

    (3):检查实例类型指令,如INSTANCEOF、CHECKCAST等

  5、操作栈管理指令

    JVM提供了直接控制操作栈的指令,常见的指令如下:

    (1):出栈操作,POP即一个元素,POP2即两个元素

    (2):复制栈顶元素并压入栈,如DUP

    

  6、方法调用与返回指令

    INVOKEVIRTUAL:调用对象的实例方法

    INVOKESPECIAL:调用实例初始化方法、私有方法、父类方法等

    INVOKESTATIC:调用类静态方法

    RETURN:返回VOID类型

  7、同步指令

    JVM使用方法结构中的ACC_SYNCHRONIZED 标识同步方法。会在同步块的前后分别形成MONITORENTER和MONITOREXIT两个字节码指令。

    MONITORENTER:尝试获取锁,获取成功,锁计数器(monitor,位于对象头中)计数器加1

    MONITOREXIT:释放锁,锁计数器 monitor减1

END.

原文地址:https://www.cnblogs.com/yangyongjie/p/14574877.html