JVM学习笔记(一)

首先对.java文件进行编译获得对应的.class文件(使用命令javac xxx.java),在.java同级目录下生成相应.class文件。之后我们执行javap -verbose xxx.class,可以查看到常量池信息,字节码文件需要下载winhex软件查看,如下图所示:

public class NoWhileBlockTest{
	private int a = 1;
	public void B(){
		while(true) a++;
	}
}

  

Classfile /D:/tmp/NoWhileBlockTest.class
  Last modified 2019-11-12; size 321 bytes
  MD5 checksum e2b29d17b6e74e6de24a2976634af41d
  Compiled from "NoWhileBlockTest.java"
public class NoWhileBlockTest
  minor version: 0
  major version: 52
  flags: ACC_PUBLIC, ACC_SUPER
Constant pool:
   #1 = Methodref          #4.#15         // java/lang/Object."<init>":()V
   #2 = Fieldref           #3.#16         // NoWhileBlockTest.a:I
   #3 = Class              #17            // NoWhileBlockTest
   #4 = Class              #18            // java/lang/Object
   #5 = Utf8               a
   #6 = Utf8               I
   #7 = Utf8               <init>
   #8 = Utf8               ()V
   #9 = Utf8               Code
  #10 = Utf8               LineNumberTable
  #11 = Utf8               B
  #12 = Utf8               StackMapTable
  #13 = Utf8               SourceFile
  #14 = Utf8               NoWhileBlockTest.java
  #15 = NameAndType        #7:#8          // "<init>":()V
  #16 = NameAndType        #5:#6          // a:I
  #17 = Utf8               NoWhileBlockTest
  #18 = Utf8               java/lang/Object
{
  public NoWhileBlockTest();
    descriptor: ()V
    flags: ACC_PUBLIC
    Code:
      stack=2, locals=1, args_size=1
         0: aload_0
         1: invokespecial #1                  // Method java/lang/Object."<init>":()V
         4: aload_0
         5: iconst_1
         6: putfield      #2                  // Field a:I
         9: return
      LineNumberTable:
        line 1: 0
        line 2: 4

  public void B();
    descriptor: ()V
    flags: ACC_PUBLIC
    Code:
      stack=3, locals=1, args_size=1
         0: aload_0
         1: dup
         2: getfield      #2                  // Field a:I
         5: iconst_1
         6: iadd
         7: putfield      #2                  // Field a:I
        10: goto          0
      LineNumberTable:
        line 4: 0
      StackMapTable: number_of_entries = 1
        frame_type = 0 /* same */
}
SourceFile: "NoWhileBlockTest.java"

 

 

 

每一个字节码文件对应一个ClassFile结构,其描述信息如下:

1. magic number(CA FE BA BE) : 一个有效字节码文件的前四个字节为 0xCAFEBABE,被称为魔术(magic number)。之所以JVM不采用后缀名.class区分,是为了防止用户擅自修改后缀名。

2. minor_version和major_version(00 00 00 34) : 确定字节码文件的主次版本号,高版本JVM编译的字节码文件无法被低版本JVM处理(抛出java.lang.UnsupportedClassVersionError),但高版本JVM会向下兼容运行低版本JVM编译的字节码文件。

3. constant_pool_count和constant_pool : 常量计数器和常量池。在上面字节码中常量计数器表示为 00 13,JVM的常量计数器从1开始(0仍存在,表示后续类不引用常量池中任何常量时的访问索引)。换算后程序中有19-1=18个常量,如javap -verbose结果所示。

  常量池中存放两类数据,分别为字面量和符号引用,具体包含内容如表所示:

字面量 文字字符串、final常量值
符号引用

类和接口的全限定名、字段名称和描述符、方法名称和描述符

4. access_fiags : 访问标志,占两字节,表示字节码文件表示的是类、接口、注解还是枚举。在javap -verbose中表示为:

 

 它表示该类是public且可以调用父类。

5. this_class和supper_class : 4字节的类索引和超类索引。分别通过索引指向常量池列表中一个类型为CONSTANT_CLASS_info的常量项。

6. interfaces_count和interfaces : 4字节的接口计数器和接口表。接口计数器用于表示当前类或接口的直接超类接口数量,从0开始计数。而接口表实际上是一个数组集合,包含了当前类或接口在常量池列表中直接超类接口的索引集合,这个索引可以确定当前类或接口的全限定名。

7. fields_count和fields : 字段计数器和字段表。表示当前类或接口中的字段,不包含继承超类中的字段。字段表中每个成员必须是field_info结构的数据项,它表明字段的标识符、public或private或protected、static、final。

8. method_count和methods : 方法计数器和方法表。

9. attributes_count和attributes : 属性计数器和属性表。

 

参考:《Java虚拟机精讲》

   https://blog.csdn.net/zuoyouzouzou/article/details/91346848

 

posted @ 2019-11-12 19:58  haodi  阅读(150)  评论(0)    收藏  举报