1. 虚拟机组成
Java虚拟机主要分为以下几个组成部分:
- 类加载子系统:核心组件类加载器,负责将字节码文件中的内容加载到内存中。
- 运行时数据区:JVM管理的内存,创建出来的对象、类的信息等等内容都会放在这块区域中。
- 执行引擎:包含了即时编译器、解释器、垃圾回收器,执行引擎使用解释器将字节码指令解释成机器码,使用即时编译器优化性能,使用垃圾回收器回收不再使用的对象。
- 本地接口:调用本地使用C/C++编译好的方法,本地方法在Java中声明时,都会带上native关键字,如下图所示。
2. 字节码组成
字节码文件总共可以分为以下几个部分:
- 基础信息:魔数、字节码文件对应的Java版本号、访问标识(public final等等)、父类和接口信息
- 常量池:保存了字符串常量、类或接口名、字段名,主要在字节码指令中使用
- 字段: 当前类或接口声明的字段信息
- 方法: 当前类或接口声明的方法信息,核心内容为方法的字节码指令
- 属性: 类的属性,比如源码的文件名、内部类的列表等
2.1. 基础信息
Magic魔数
每个Java字节码文件的前四个字节是固定的,用16进制表示就是0xcafebabe。文件是无法通过文件扩展名来确定文件类型的,文件扩展名可以随意修改不影响文件的内容。软件会使用文件的头几个字节(文件头)去校验文件的类型,如果软件不支持该种类型就会出错。
java版本号
主副版本号指的是编译字节码文件时使用的JDK版本号,主版本号用来标识大版本号,JDK1.0-1.1使用了45.0-45.3,JDK1.2是46之后每升级一个大版本就加1;副版本号是当主版本号相同时作为区分不同版本的标识,一般只需要关心主版本号。
JDK1.2之后大版本号计算方法就是 : JDK1主版本号为44,JDK8主版本号为52。
版本号的作用主要是判断当前字节码的版本和运行时的JDK是否兼容。
访问标识
标识是类还是接口、注解、枚举、模块标识public final abstract
类、父类、接口索引
通过这些索引可以找到类、父类、接口的信息
2.2. 常量池
字节码文件中常量池的作用:避免相同的内容重复定义,节省空间。
字节码指令中通过编号引用到常量池的过程称之为符号引用。
2.3. 字段
字段中存放的是当前类或接口声明的字段信息。
2.4. 属性
属性主要指的是类的属性,比如源码的文件名、内部类的列表等。
2.5. 方法
字节码中的方法区是存放字节码指令的核心位置,字节码指令的内容存放在方法的Code属性中。
操作数栈(operand stack):用于存储执行过程中的操作数和部分结果。
局部变量表(local variable table):用于存储函数内部定义的局部变量。
当函数或方法被调用时,会创建一个新的局部变量表,用于存储该函数内部的局部变量。在执行函数体时,局部变量表和操作数栈会协同工作,局部变量表用于存储变量,而操作数栈用于执行具体的计算操作。
int i = 0; int j = i + 1; //res,j = 1 //class 0 iconst_0 1 istore_1 2 iload_1 3 iconst_1 4 iadd 5 istore_2 6 return ========================================== int i = 0; i = i++; //res,i = 0 //class //将0放入操作数栈 0 iconst_0 //从操作数栈取出放入局部变量表1号位置 1 istore_1 //从局部变量表1号位置加载数据到操作数栈 2 iload_1 //在局部变量表1号位置增加1 3 iinc 1 by 1 //将操作数栈中的值保存到局部变量表 6 istore_1 7 return ========================================== int i = 0; i = ++i; //res,i = 1 //class 0 iconst_0 1 istore_1 2 iinc 1 by 1 5 iload_1 6 istore_1 7 return ========================================== int i=0,j=0,k=0; i++; j = j+ 1; k += 1; //已知字节码命令行数越多,性能越低;分析上面指令性能高低 0 iconst_0 1 istore_1 2 iconst_0 3 istore_2 4 iconst_0 5 istore_3 6 iinc 1 by 1 9 iload_2 10 iconst_1 11 iadd 12 istore_2 13 iinc 3 by 1 16 return //可知,性能排序 i++ = k += 1 >> j = j+ 1
3. 字节码工具
3.1. javap
javap是JDK自带的反编译工具,可以通过控制台查看字节码文件的内容。适合在服务器上查看字节码文件内容。
直接输入javap查看所有参数。输入javap -v 字节码文件名称 查看具体的字节码信息。如果jar包需要先使用 jar –xvf 命令解压。
//解压jar包 jar -xvf user-service.jar //查看指定字节码文件,并将内容输出到指定文件 javap -v /opt/jvm/B00T-INF/classes/comitheima/springbootclassfile/pojo/vo/Userv0.class > /opt/jvm/UseVo.txt
3.2. jclasslib
jclasslib软件 以及 idea中自带jclasslib插件
3.3. Arthas
(待补充)