JVM 知识体系
问题1: Java 是编译执行的还是解释执行的?
解释 + 热点代码编译 执行 (混合执行)
**解析:**其实 JVM 主要对 class 文件中的字节码使用 字节码解释器
进行解释并执行。但是当某一方法调用次数达到即时编译定义的阈值时,就会触发即时编译,这时即时编译器会将IR进行优化,并生成这个方法的机器码,后面再调用这个方法,就会直接调用机器码执行
相关参数:
-Xmixed
混合执行-Xint
解释执行模式-Xcomp
编译执行模式
JVM
对上层,屏蔽了语言的差异,只要是能被翻译成符合 Class
文件标准的,均可以被 JVM
执行。JVM
规范与 JVM
体系是独立于 Java 之外的,虽然它被称作 java virtual machine
。
对下层,JVM
屏蔽了操作系统的差异,对于操作系统而言,JVM
也只不过是运行在其上的一个应用程序而已。
JVM
是一种规范,并且这种规范很像是一个小的操作系统。它有自己的指令集,内存管理,词法分析器,语法分析器,语义分析器,抽象语法树,字节码生成器,注解抽象语法树等。
常见的 JVM
实现
HotSpot
Jrockit
(已被Oracle收购,并且其相关能力已经并入 Hotspot)J9
- IBMMicrosoft-VM
Taobao-VM
(Hotspot 的深度定制版)LiquidVM
(直接针对硬件)Azul zing
(土豪机 - 拥有最快垃圾回收的业界标杆) Azul
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
};
{
"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 Kind | Tag | class file format | Java SE |
---|---|---|---|
CONSTANT_Utf8 | 1 | 45.3 | 1.0.2 |
CONSTANT_Integer | 3 | 45.3 | 1.0.2 |
CONSTANT_Float | 4 | 45.3 | 1.0.2 |
CONSTANT_Long | 5 | 45.3 | 1.0.2 |
CONSTANT_Double | 6 | 45.3 | 1.0.2 |
CONSTANT_Class | 7 | 45.3 | 1.0.2 |
CONSTANT_String | 8 | 45.3 | 1.0.2 |
CONSTANT_Fieldref | 9 | 45.3 | 1.0.2 |
CONSTANT_Methodref | 10 | 45.3 | 1.0.2 |
CONSTANT_InterfaceMethodref | 11 | 45.3 | 1.0.2 |
CONSTANT_NameAndType | 12 | 45.3 | 1.0.2 |
CONSTANT_MethodHandle | 15 | 51.0 | 7 |
CONSTANT_MethodType | 16 | 51.0 | 7 |
CONSTANT_Dynamic | 17 | 55.0 | 11 |
CONSTANT_InvokeDynamic | 18 | 51.0 | 7 |
CONSTANT_Module | 19 | 53.0 | 9 |
CONSTANT_Package | 20 | 53.0 | 9 |
/**
* 常量池中的内容
*/
@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_index
和 attribute_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;
}
}