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

浙公网安备 33010602011771号