关于Java虚拟机中的字节码指令

翻译 2007年09月24日 11:06:00

                           字节码

源代码经过编译器编译之后便会生成一个字节码文件,字节码是一种二进制的类文件,它的内容是JVM的指令,而不像CC++经由编译器直接生成机器码。我们不用担心生成的字节码文件的兼容性,因为所有的JVM全部遵守Java虚拟机规范,也就是说所有的JVM环境都是一样的,这样一来字节码文件可以在各种JVM上运行。 当然也包括KVM

每一个线程都有一个保存帧的栈。在每一个方法调用的时候创建一个帧。一个帧包括了三个部分:操作栈,局部变量数组,和一个对当前方法所属类的常量池的引用。

局部变量数组也被称之为局部变量表,它包含了方法的参数,也用于保存一些局部变量的值。参数值得存放总是在局部变量数组的index0开始的。如果当前帧是由构造函数或者实例方法创建的,那么该对象引用将会存放在location0处,然后才开始存放其余的参数。

局部变量表的大小由编译时决定,同时也依赖于局部变量的数量和一些方法的大小。操作栈是一个(LIFO)栈,用于压入和取出值,其大小也在编译时决定。某些opcode指令将值压入操作栈,其余的opcode指令将操作数取出栈。使用它们后再把结果压入栈。操作栈也用于接收从方法中返回的值。

HelloWorld程序为例,经过命令:

E:/JavaExe>javap -c HelloWorld>HelloWorld.bytecode

就会在目录下生成一个字节码文件,用编辑器打开后

 

Compiled from "HelloWorld.java"

class HelloWorld extends java.lang.Object{

public HelloWorld(java.lang.String,int);

  Code:

   0:      aload_0

   1:      invokespecial #1; //Method java/lang/Object."<init>":()V

   4:      aload_0

   5:      ldc   #2; //String

   7:      putfield   #3; //Field name:Ljava/lang/String;

   10:    aload_0

   11:    iconst_0

   12:    putfield   #4; //Field idNumber:I

   15:    aload_0

   16:    aload_1

   17:    putfield   #3; //Field name:Ljava/lang/String;

   20:    aload_0

   21:    iload_2

   22:    putfield   #4; //Field idNumber:I

   25:    aload_0

   26:    aload_1

   27:    iload_2

   28:    invokevirtual  #5; //Method StoreData:(Ljava/lang/String;I)V

   31:    return

 

public void StoreData(java.lang.String,int);

  Code:

   0:      bipush    90

   2:      istore_2

   3:      return

 

void print(AnotherClass);

  Code:

   0:      aload_1

   1:      bipush    10

   3:      putfield   #6; //Field AnotherClass.a:I

   6:      new #7; //class AnotherClass

   9:      dup

   10:    invokespecial #8; //Method AnotherClass."<init>":()V

   13:    astore_1

   14:    aload_1

   15:    bipush    20

   17:    putfield   #6; //Field AnotherClass.a:I

   20:    return

 

}

 

以上是经过编译后的HelloWorld的字节码文件。我们可以对照源文件来查看一些重要的指令。

class HelloWorld

{

     private   String name = "";

     private  int idNumber = 0;

     public HelloWorld(String strName, int num)

     {

      

        name = strName;

        idNumber = num;

        StoreData(strName,num);

     }

  public  void StoreData(String str,int i)

  {

        i = 90;

  }

  void print(AnotherClass another)

  {

         another.a=10;

         another=new AnotherClass();

         another.a=20;

   }

 

}

class AnotherClass

{

    public int a = 0;

   

}

void print(AnotherClass);

  Code:

   0:      aload_1

   1:      bipush    10

   3:      putfield   #6; //Field AnotherClass.a:I

   6:      new #7; //class AnotherClass

   9:      dup

   10:    invokespecial #8; //Method AnotherClass."<init>":()V

   13:    astore_1

   14:    aload_1

   15:    bipush    20

   17:    putfield   #6; //Field AnotherClass.a:I

   20:    return

 

aload_1 把存放在局部变量表中索引1位置的对象引用压入操作栈

bipush 10 把整数10压入栈

putfield #2 把成员变量a的值设置成栈中的10#2代表2号常量项

new #3 创建AnotherClass的对象,把引用放入栈

dup 复制刚放入的引用(这时存在着两个相同的引用)

invokespecial #4 通过其中的一个引用调用AnotherClass的构造器,初始化对象,让另一个相同引用指向初始化的对象,然后前一个引用(this)弹出栈

asstore_1 把引用保存到局部变量表中的索引1位置中,然后引用弹出栈

aload_1 把局部变量表中索引1处的值压入操作栈。

bipush 20 把整数20压入栈

putfield #2 把成员变量a的值设置成栈中的10

return 执行完毕退出

 

我们继续看构造函数中的一段代码:

public HelloWorld(java.lang.String,int);

  Code:

将该(this)对象压入操作栈,对于实例方法和构造函数的局部变量表来说第一个入口总是这个“this”。因为你需要访问一些实例中的方法和变量。

   0:      aload_0 

   调用该类的超类构造函数,因为所有类都继承与Java.lang.Object。而该类(HelloWorld)没有new函数操作,所以编译器提供必要的字节码来调用这些基类构造器。

   1:      invokespecial #1; //Method java/lang/Object."<init>":()V

   将该(this)对象压入操作栈

4:    aload_0

字符串

    5:    ldc   #2; //String abc

把栈中的name的值置为栈中的”abc”

   7:      putfield   #3; //Field name:Ljava/lang/String;

   同样,将this压入栈

   10:    aload_0

   0压入栈。

   11:    iconst_0

   idNumber置为栈中的0,就是上一句指令中的操作

   12:    putfield   #4; //Field idNumber:I

   this压入栈

   15:    aload_0

   将位于局部变量表中位置1处的方法的形参strName压入栈

   16:    aload_1

   name的值置为栈中的strName

   17:    putfield   #3; //Field name:Ljava/lang/String;

   this压入栈,this总是位于局部变量表的index0处!

   20:    aload_0

   将位于局部变量表中位置2处的方法形参num压入栈

   21:    iload_2

   17号操作,赋值

   22:    putfield   #4; //Field idNumber:I

   this压入操作栈

   25:    aload_0

   strName压入栈

   26:    aload_1

num压入栈

   27:    iload_2

   调用方法StoreData

   28:    invokevirtual  #5; //Method StoreData:(Ljava/lang/String;I)V

   31:    return

  如果有()V 标志方法没有参数列表

我们观察发现,在每一个opcode指令的左边的位置序号都不是连续的。0,1,4,5,7,10……为什么?

每一个方法都有一个对应得ByteCode序列,这些值对应着每一个opcode和其参数存放的序列中的某一个索引值。为什么这些索引不是顺序的?既然每一个指令占据一个字节,那索引为什么不是012呢?原因是:一些指令的参数占据了一些bytecode数组空间。比如:

Aload_0指令没有参数,所以占有一个字节,第二个指令invokespecial,由于它本身带有参数,结果它本身和参数分别就占据了一个位置,所以,上面的1过了就不是4。

 

Aload_0

invokespecial

00

05

return

 

 

相关文章推荐

JVM指令详解(下)

九、自增减指令 该指令用于对本地(局部)变量进行自增减操作。该指令第一参数为本地变量的编号,第二个参数为自增减的数量。 比如对于代码:                 int d=10; ...
  • hudashi
  • hudashi
  • 2011年12月12日 10:49
  • 4753

java.io.ObjectOutputStream.putFields()和java.io.ObjectInputStream. readFields()

在自定义序列化和反序列化时,java.io.ObjectOutputStream.putFields()和java.io.ObjectInputStream.readFields()非常有用。 a)...

Java虚拟机字节码指令

Java字节码指令 Java 字节码指令及javap 使用说明 ### java字节码指令列表 字节码 助记符 指令含义 0x00 nop 什么都不做 0x01 ...

java 字节码 指令集 汇编

常量入栈指令 指令码 操作码(助记符) 操作数 描述(栈指操作数栈) 0x01 aconst_null   null值入栈。 0x02 iconst_m1...

Java字节码指令集的使用详细

本篇文章对Java字节码指令集的使用进行了详细的介绍。需要的朋友参考下   Java虚拟机指令由一个字节长度的、代表某种特定含义的操作码(Opcode)以及其后的零个至多个代表此操作参数的操作数构成。...

常见 Java 字节码 指令 助记符

转自: 常见java字节码 有时候为了能理解JVM对程序所做的优化等,需要查看程序的字节码,因此知道了解一些常见的指令集很重要! 指令码 ...

Java字节码指令集

字节码指令集   Java虚拟机的指令由一个字节长度的、代表着某种特定操作含义的操作码(Opcode)以及跟随其后的零至多个代表此操作所需参数的操作数(Operands)所构成。   对于大部分为...
  • novelly
  • novelly
  • 2013年11月15日 19:06
  • 1470

java字节码指令列表

Mnemonic Opcode (in hex) Other bytes Stack [before]→[after] Description aaloa...
  • ygc87
  • ygc87
  • 2013年10月22日 20:29
  • 6825

关于计时器定时器的设计 时间轮的高效实现 linux hashed Hierarchical timing wheel

关于时间轮的设计 linux hashed Hierarchical timing wheel 异步定时任务执行器
  • collonn
  • collonn
  • 2017年01月18日 18:15
  • 812

【算法】4 五张图带你体会堆算法

什么是堆堆(heap),是一类特殊的数据结构的统称。它通常被看作一棵树的数组对象。在队列中,调度程序反复提取队列中的第一个作业并运行,因为实际情况中某些时间较短的任务却可能需要等待很长时间才能开始执行...
  • NoMasp
  • NoMasp
  • 2015年05月31日 23:09
  • 9862
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:关于Java虚拟机中的字节码指令
举报原因:
原因补充:

(最多只允许输入30个字)