JVM_01 Class文件格式

JVM 知识体系

在这里插入图片描述

图1 jvm 结构
问题1: Java 是编译执行的还是解释执行的?

解释 + 热点代码编译 执行 (混合执行)

**解析:**其实 JVM 主要对 class 文件中的字节码使用 字节码解释器 进行解释并执行。但是当某一方法调用次数达到即时编译定义的阈值时,就会触发即时编译,这时即时编译器会将IR进行优化,并生成这个方法的机器码,后面再调用这个方法,就会直接调用机器码执行

相关参数:

  • -Xmixed 混合执行
  • -Xint 解释执行模式
  • -Xcomp 编译执行模式

在这里插入图片描述

图2 jvm 地位

JVM 对上层,屏蔽了语言的差异,只要是能被翻译成符合 Class 文件标准的,均可以被 JVM 执行。JVM 规范与 JVM 体系是独立于 Java 之外的,虽然它被称作 java virtual machine

​ 对下层,JVM 屏蔽了操作系统的差异,对于操作系统而言,JVM 也只不过是运行在其上的一个应用程序而已。

JVM 是一种规范,并且这种规范很像是一个小的操作系统。它有自己的指令集,内存管理,词法分析器,语法分析器,语义分析器,抽象语法树,字节码生成器,注解抽象语法树等。

常见的 JVM 实现
  • HotSpot
  • Jrockit (已被Oracle收购,并且其相关能力已经并入 Hotspot)
  • J9 - IBM
  • Microsoft-VM
  • Taobao-VM (Hotspot 的深度定制版)
  • LiquidVM (直接针对硬件)
  • Azul zing (土豪机 - 拥有最快垃圾回收的业界标杆) Azul
Java结构

在这里插入图片描述

图3 java 结构
* JVM
* JRE(Java runtime enviroment) = JVM + coreLib (String Object 等)
* JDK(Java development Kit) = JRE + development Kit

Class文件格式

官方文档

// 一个空类的示例
private static int[] byteCode = new int[]{
            // u4 magic
            0xca, 0xfe, 0xba, 0xbe,
            // u2 minor_version = 0
            0x00, 0x00,
            // u2 major_version = 52
            0x00, 0x34,
            // u2 constant_pool_count = 16
            0x00, 0x10,
            // constant pool
            0x0a, 0x00, 0x03, 0x00, 0x0d, 0x07,
            0x00, 0x0e, 0x07, 0x00, 0x0f, 0x01, 0x00, 0x06, 0x3c, 0x69, 0x6e, 0x69, 0x74, 0x3e, 0x01, 0x00,
            0x03, 0x28, 0x29, 0x56, 0x01, 0x00, 0x04, 0x43, 0x6f, 0x64, 0x65, 0x01, 0x00, 0x0f, 0x4c, 0x69,
            0x6e, 0x65, 0x4e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x54, 0x61, 0x62, 0x6c, 0x65, 0x01, 0x00, 0x12,
            0x4c, 0x6f, 0x63, 0x61, 0x6c, 0x56, 0x61, 0x72, 0x69, 0x61, 0x62, 0x6c, 0x65, 0x54, 0x61, 0x62,
            0x6c, 0x65, 0x01, 0x00, 0x04, 0x74, 0x68, 0x69, 0x73, 0x01, 0x00, 0x12, 0x4c, 0x63, 0x6f, 0x6d,
            0x2f, 0x69, 0x6d, 0x70, 0x72, 0x6f, 0x76, 0x65, 0x2f, 0x54, 0x65, 0x73, 0x74, 0x3b, 0x01, 0x00,
            0x0a, 0x53, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x46, 0x69, 0x6c, 0x65, 0x01, 0x00, 0x09, 0x54, 0x65,
            0x73, 0x74, 0x2e, 0x6a, 0x61, 0x76, 0x61, 0x0c, 0x00, 0x04, 0x00, 0x05, 0x01, 0x00, 0x10, 0x63,
            0x6f, 0x6d, 0x2f, 0x69, 0x6d, 0x70, 0x72, 0x6f, 0x76, 0x65, 0x2f, 0x54, 0x65, 0x73, 0x74, 0x01,
            0x00, 0x10, 0x6a, 0x61, 0x76, 0x61, 0x2f, 0x6c, 0x61, 0x6e, 0x67, 0x2f, 0x4f, 0x62, 0x6a, 0x65,
            0x63, 0x74, 0x00, 0x21, 0x00, 0x02, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x01,
            0x00, 0x04, 0x00, 0x05, 0x00, 0x01,
            // #6 = Code
            0x00, 0x06,
            // Code 长度 = 47
            0x00, 0x00, 0x00, 0x2f,
            // max_stacks
            0x00, 0x01,
            // max_locals
            0x00, 0x01,
            // 命令长度
            0x00, 0x00, 0x00, 0x05,
            // 5个命令(实际是3个命令 + 两个参数)
            0x2a, 0xb7, 0x00, 0x01, 0xb1,
            // exception_table 长度
            0x00, 0x00,
            // attribute_count = 2
            0x00, 0x02,

            0x00, 0x07, 0x00, 0x00, 0x00, 0x06,
            // content
            0x00, 0x01, 0x00, 0x00, 0x00, 0x0a,
            0x00, 0x08, 0x00, 0x00, 0x00, 0x0c,
            // content
            0x00, 0x01, 0x00, 0x00, 0x00, 0x05, 0x00, 0x09, 0x00, 0x0a, 0x00, 0x00,

            0x00, 0x01,

            0x00, 0x0b, 0x00,
            0x00, 0x00, 0x02, 0x00, 0x0c
    };

使用 自定义解析工具 解析出的 Class 文件内容

{
    "accessFlags":[
        "ACC_SUPER",
        "ACC_PUBLIC"
    ],
    "attributes":[
        {
            "attribute_length":2,
            "attribute_name_index":1,
            "sourcefile_index":12
        }
    ],
    "attributesCount":1,
    "constantPool":{
        "1":{
            "class_index":3,
            "name_and_type_index":13,
            "tag":10
        },
        "2":{
            "name_index":14,
            "tag":7
        },
        "3":{
            "name_index":15,
            "tag":7
        },
        "4":{
            "content":"<init>",
            "length":6,
            "tag":1
        },
        "5":{
            "content":"()V",
            "length":3,
            "tag":1
        },
        "6":{
            "content":"Code",
            "length":4,
            "tag":1
        },
        "7":{
            "content":"LineNumberTable",
            "length":15,
            "tag":1
        },
        "8":{
            "content":"LocalVariableTable",
            "length":18,
            "tag":1
        },
        "9":{
            "content":"this",
            "length":4,
            "tag":1
        },
        "10":{
            "content":"Lcom/improve/Test;",
            "length":18,
            "tag":1
        },
        "11":{
            "content":"SourceFile",
            "length":10,
            "tag":1
        },
        "12":{
            "content":"Test.java",
            "length":9,
            "tag":1
        },
        "13":{
            "descriptor_index":5,
            "name_index":4,
            "tag":12
        },
        "14":{
            "content":"com/improve/Test",
            "length":16,
            "tag":1
        },
        "15":{
            "content":"java/lang/Object",
            "length":16,
            "tag":1
        }
    },
    "constantPoolCount":16,
    "fields":[

    ],
    "fieldsCount":0,
    "interfaces":[

    ],
    "interfacesCount":0,
    "magicNumber":"cafebabe",
    "majorVersion":52,
    "methods":[
        {
            "access_flags":[
                "ACC_PUBLIC"
            ],
            "attributes":[
                {
                    "attribute_length":47,
                    "attribute_name_index":1,
                    "attributes":[
                        {
                            "attribute_length":6,
                            "attribute_name_index":1,
                            "line_number_table":[
                                {
                                    "line_number":10,
                                    "start_pc":0
                                }
                            ],
                            "line_number_table_length":1
                        },
                        {
                            "attribute_length":12,
                            "attribute_name_index":1,
                            "local_variable_table":[
                                {
                                    "descriptor_index":10,
                                    "index":0,
                                    "length":5,
                                    "name_index":9,
                                    "start_pc":0
                                }
                            ],
                            "local_variable_table_length":1
                        }
                    ],
                    "attributes_count":2,
                    "code":[
                        42,
                        183,
                        0,
                        1,
                        177
                    ],
                    "code_length":5,
                    "exception_table":[

                    ],
                    "exception_table_length":0,
                    "max_locals":1,
                    "max_stack":1
                }
            ],
            "attributes_count":1,
            "descriptor_index":5,
            "name_index":4
        }
    ],
    "methodsCount":1,
    "minorVersion":0,
    "superClass":3,
    "thisClass":2
}

在官方定义中,使用 u 代表占用字节数 (unsigned) 。

u1 - 一字节

u2 - 二字节

u4 - 四字节

// Class 文件格式
ClassFile {
 u4 magic;																			// class 文件的唯一标识 - ca fe ba be
 u2 minor_version;															// 副 - 版本号
 u2 major_version;															// 主 - 版本号
 u2 constant_pool_count;												// 常量池 大小
 cp_info constant_pool[constant_pool_count-1];	// 常量池内容 大小为 constant_pool_count-1
 u2 access_flags;																// 访问标识
 u2 this_class;																	// 本类 - 为指向常量池编号的数值
 u2 super_class;																// 父类 - 为指向常量池编号的数值
 u2 interfaces_count;														// 实现的接口数
 u2 interfaces[interfaces_count];								// 都有哪些接口 - 为指向常量池编号的数值
 u2 fields_count;																// 字段数量
 field_info fields[fields_count];								// 字段详情
 u2 methods_count;															// 方法数量
 method_info methods[methods_count];						// 方法详情
 u2 attributes_count;														// 属性数量
 attribute_info attributes[attributes_count];		// 属性详情
}
cp_info
cp_info {
 u1 tag;
 u1 info[];
}

​ 官方文档中给出的 cp_info 格式如上,实际上常量池中的 item有以下 17 种,它们的格式除了相同的 tag 外都不相同;

Constant KindTagclass file formatJava SE
CONSTANT_Utf8145.31.0.2
CONSTANT_Integer345.31.0.2
CONSTANT_Float445.31.0.2
CONSTANT_Long545.31.0.2
CONSTANT_Double645.31.0.2
CONSTANT_Class745.31.0.2
CONSTANT_String845.31.0.2
CONSTANT_Fieldref945.31.0.2
CONSTANT_Methodref1045.31.0.2
CONSTANT_InterfaceMethodref1145.31.0.2
CONSTANT_NameAndType1245.31.0.2
CONSTANT_MethodHandle1551.07
CONSTANT_MethodType1651.07
CONSTANT_Dynamic1755.011
CONSTANT_InvokeDynamic1851.07
CONSTANT_Module1953.09
CONSTANT_Package2053.09
		/**
     * 常量池中的内容
     */
    @Data
    public static class CpInfo {

        // u1
        private int tag;

        /*
         * 具体内容由子类实现
         */
        // private int[] info;
    }

    @Getter
    @Setter
    public static class CONSTANT_Utf8_info extends CpInfo {
        /*
        UTF-8 info 存储的是一个 字符串
    
               CONSTANT_Utf8_info {
                 u1 tag;
                 u2 length;
                 u1 bytes[length];
                }
         */
        private Integer length;
        private String content;
    }

    @Getter
    @Setter
    public static class CONSTANT_Integer_info extends CpInfo {
        /*
        Integer_info 存储一个 INT 值
        
                CONSTANT_Integer_info {
                 u1 tag;
                 u4 bytes;
                }
         */
        private Integer content;
    }

    @Getter
    @Setter
    public static class CONSTANT_Float_info extends CpInfo {
        /*
        Float_info 存储一个 Float 值
        
                CONSTANT_Float_info {
                 u1 tag;
                 u4 bytes;
                }
         */
        private Float content;
    }

    @Getter
    @Setter
    public static class CONSTANT_Long_info extends CpInfo {
        /*
        Long 和 Double 是8字节的,需要将高4位和低4位分开存储
        
                CONSTANT_Long_info {
                 u1 tag;
                 u4 high_bytes;
                 u4 low_bytes;
                }
        */
        private Long content;
    }

    @Getter
    @Setter
    public static class CONSTANT_Double_info extends CpInfo {
        /*
                CONSTANT_Double_info {
                 u1 tag;
                 u4 high_bytes;
                 u4 low_bytes;
                }
         */
        private Double content;
    }

    @Getter
    @Setter
    public static class CONSTANT_Class_info extends CpInfo {
        /*
                CONSTANT_Class_info {
                 u1 tag;
                 u2 name_index;
                }
         */
        // 指向常量池中一个 CONSTANT_Utf8_info
        private Integer name_index;
    }

    @Getter
    @Setter
    public static class CONSTANT_String_info extends CpInfo {
        /*
                CONSTANT_String_info {
                 u1 tag;
                 u2 string_index;
                }
         */
        // 指向常量池中一个 CONSTANT_Utf8_info
        private Integer string_index;
    }

    @Getter
    @Setter
    public static class CONSTANT_Fieldref_info extends CpInfo {
        /*
                CONSTANT_Fieldref_info {
                 u1 tag;
                // 指向常量池中一个 CONSTANT_Class_info
                 u2 class_index;
                // 指向常量池中一个 CONSTANT_NameAndType_info
                 u2 name_and_type_index;
                }
         */
        private CONSTANT_Class_info class_index;
        private CONSTANT_NameAndType_info name_and_type_index;
    }

    @Getter
    @Setter
    public static class CONSTANT_Methodref_info extends CpInfo {
        /*
                CONSTANT_Methodref_info {
                 u1 tag;
                 u2 class_index;
                 u2 name_and_type_index;
                }
         */
      	// 指向常量池中一个 Class 类型的常量
        private Integer class_index;
      	// 指向常量池中一个 NameAnyType 类型的常量
        private Integer name_and_type_index;
    }

    @Getter
    @Setter
    public static class CONSTANT_InterfaceMethodref_info extends CpInfo {
        /*
                CONSTANT_InterfaceMethodref_info {
                 u1 tag;
                 u2 class_index;
                 u2 name_and_type_index;
                }
         */
        private CONSTANT_Class_info class_index;
        private CONSTANT_NameAndType_info name_and_type_index;
    }

    @Getter
    @Setter
    public static class CONSTANT_NameAndType_info extends CpInfo {
        /*
                CONSTANT_NameAndType_info {
                 u1 tag;
                 u2 name_index;     // CONSTANT_Utf8_info
                 u2 descriptor_index;       // CONSTANT_Utf8_info
                }
         */
        private Integer name_index;
        private Integer descriptor_index;
    }

    @Getter
    @Setter
    public static class CONSTANT_MethodHandle_info extends CpInfo {
        /*
                CONSTANT_MethodHandle_info {
                 u1 tag;
                 u1 reference_kind;
                 u2 reference_index;
                }
         */
        private ReferenceKindEnum reference_kind;
        // 有规定,要看 ReferenceKindEnum 中的
        private ConstantPoolTagEnum reference_index;
    }

    @Getter
    @Setter
    public static class CONSTANT_MethodType_info extends CpInfo {
        /*
                CONSTANT_MethodType_info {
                 u1 tag;
                 u2 descriptor_index;   // CONSTANT_Utf8_info
                }
         */
        private CONSTANT_Utf8_info descriptor_index;
    }

    @Getter
    @Setter
    public static class CONSTANT_Dynamic_info extends CpInfo {
        /*
                CONSTANT_Dynamic_info {
                 u1 tag;
                 u2 bootstrap_method_attr_index;
                 u2 name_and_type_index;
                }
         */
        // valid index into the bootstrap_methods
        private Integer bootstrap_method_attr_index;
        private CONSTANT_NameAndType_info name_and_type_index;
    }

    @Getter
    @Setter
    public static class CONSTANT_InvokeDynamic_info extends CpInfo {
        /*
                CONSTANT_InvokeDynamic_info {
                 u1 tag;
                 u2 bootstrap_method_attr_index;
                 u2 name_and_type_index;
                }
         */

        // valid index into the bootstrap_methods
        private int bootstrap_method_attr_index;
        private CONSTANT_NameAndType_info name_and_type_index;
    }

    @Getter
    @Setter
    public static class CONSTANT_Module_info extends CpInfo {
        /*
                CONSTANT_Module_info {
                 u1 tag;
                 u2 name_index;     // CONSTANT_Utf8_info
                }
         */
        private CONSTANT_Utf8_info name_index;
    }

    @Getter
    @Setter
    public static class CONSTANT_Package_info extends CpInfo {
        /*
                CONSTANT_Package_info {
                 u1 tag;
                 u2 name_index;     // CONSTANT_Utf8_info
                }
         */
        private CONSTANT_Utf8_info name_index;
    }
access_flags

access_flags 这个标识可能存在于 Class, Field 以及 Method 中。并且这个标识的枚举值不同。在 Class 文件中使用 4字节 代表这个标识,其每一位的含义被定义如下(以 ClassAccessFlags 为例):

	/**
     * Declared public; may be accessed from outside its
     * package.
     */
    ACC_PUBLIC(0x0001),
    /**
     * Declared final; no subclasses allowed.
     */
    ACC_FINAL(0x0010),
    /**
     * Treat superclass methods specially when invoked by
     * the invokespecial instruction.
     */
    ACC_SUPER(0x0020),
    /**
     * Is an interface, not a class.
     */
    ACC_INTERFACE(0x0200),
    /**
     * Declared abstract; must not be instantiated.
     */
    ACC_ABSTRACT(0x0400),
    /**
     * Declared synthetic; not present in the source code.
     */
    ACC_SYNTHETIC(0x1000),
    /**
     * Declared as an annotation type.
     */
    ACC_ANNOTATION(0x2000),
    /**
     * Declared as an enum type.
     */
    ACC_ENUM(0x4000),
    /**
     * Is a module, not a class or interface.
     */
    ACC_MODULE(0x8000)
field_info
@Data
public class FieldInfo {
    /*
            field_info {
             u2 access_flags;
             u2 name_index;
             u2 descriptor_index;
             u2 attributes_count;
             attribute_info attributes[attributes_count];
            }
     */
    
    private List<AccessFlagFieldEnum> access_flags;

    private Integer name_index;

    private Integer descriptor_index;

    private Integer attributes_count;

    private List<AttributeBaseInfo> attributes;

}
method_info
@Data
public class MethodInfo {
    /*
            method_info {
             u2 access_flags;
             u2 name_index;
             u2 descriptor_index;
             u2 attributes_count;
             attribute_info attributes[attributes_count];
            }
     */

    private List<AccessFlagMethodEnum> access_flags;
    private Integer name_index;
    private Integer descriptor_index;
    private Integer attributes_count;
    private List<AttributeBaseInfo> attributes;
}
attribute_info
@Data
public class AttributeBaseInfo {
    
    public static final int LENGTH_INDEX = 2;
    public static final int BASE_LENGTH = 6;

    protected Integer attribute_name_index;

    protected Integer attribute_length;
}

​ 每一个标准的 attribute_info 都包含 attribute_name_indexattribute_length 。但是具体的 attribute_info 有 25 种(截止至 jdk14)不同的数据结构。这里重点介绍三种:

Code_attribute

Code_attribute 中包含的是虚拟机能直接执行的机器指令的索引;

​ 包含在 u1 code[code_length];


@Data
public class Code_attribute extends AttributeBaseInfo {
    /*
            Code_attribute {
             u2 attribute_name_index;
             u4 attribute_length;
             u2 max_stack;
             u2 max_locals;
             u4 code_length;
             u1 code[code_length];
             u2 exception_table_length;
             { u2 start_pc;
             u2 end_pc;
             u2 handler_pc;
             u2 catch_type;
             } exception_table[exception_table_length];
             u2 attributes_count;
             attribute_info attributes[attributes_count];
            }
     */
    // 这两部分内容已经在外部了
//    private Integer attribute_name_index;
//    private Integer attribute_length;
    private Integer max_stack;
    private Integer max_locals;
    private Integer code_length;
    private List<Integer> code;
    private Integer exception_table_length;
    private List<Exception_table> exception_table;
    private Integer attributes_count;
    private List<AttributeBaseInfo> attributes;


    @Data
    public static class Exception_table {
        private Integer start_pc;
        private Integer end_pc;
        private Integer handler_pc;
        private Integer catch_type;
    }

}
LineNumberTable_attribute

行号表

@Data
public class LineNumberTable_attribute extends AttributeBaseInfo {

    /*
            LineNumberTable_attribute {
             u2 attribute_name_index;
             u4 attribute_length;
             u2 line_number_table_length;
             {  u2 start_pc;
                u2 line_number;
             } line_number_table[line_number_table_length];
            }
     */

    private Integer line_number_table_length;
    private List<LineNumberTable> line_number_table;

    @Data
    public static class LineNumberTable {
        private Integer start_pc;
        private Integer line_number;
    }

}
LocalVariableTable_attributes

局部变量表 - 保存局部变量

@Data
public class LocalVariableTable_attributes extends AttributeBaseInfo {
    /*
            LocalVariableTable_attribute {
             u2 attribute_name_index;
             u4 attribute_length;
             u2 local_variable_table_length;
             { u2 start_pc;
             u2 length;
             u2 name_index;
             u2 descriptor_index;
             u2 index;
             } local_variable_table[local_variable_table_length];
            }
     */
    private Integer local_variable_table_length;
    private List<LocalVariableTable> local_variable_table;

    @Data
    public static class LocalVariableTable {
        private Integer start_pc;
        private Integer length;
        private Integer name_index;
        private Integer descriptor_index;
        private Integer index;
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值