1. 内容大纲

本章节示例代码:https://github.com/wicksonZhang/Java-Virtual-Machine/tree/main/01-chapter/src/main/java/cn/wickson/jvm/item01

本章节主要讲解的两个核心部分是:字节码的组成、字节码的常见工具 Arthas 的使用。具体内容如下:

字节码的组成

2. 如何获取字节码文件

2.1. 通过 javac 获取

例如我们首先将如下 java 代码通过指令 javac 编译成字节码文件,然后再通过 Notepad++ 以 16 进制格式打开源文件。

  • Calculator.java 源文件如下
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
/**
* Java To Class
*/
public class Calculator {
private int result;

public Calculator() {
this.result = 0;
}

public void add(int a, int b) {
this.result = a + b;
}

public void subtract(int a, int b) {
this.result = a - b;
}

public int getResult() {
return this.result;
}

public static void main(String[] args) {
Calculator calc = new Calculator();
calc.add(5, 3);
System.out.println("Result of addition: " + calc.getResult());

calc.subtract(10, 4);
System.out.println("Result of subtraction: " + calc.getResult());
}
}
  • 通过 javac 进行编译 Calculator.java
1
2
3
4
5
6
7
8
9
D:\idea-project\Java-Virtual-Machine\01-chapter\src\main\java\cn\wickson\jvm\item01>dir /a /w
...
Calculator.java

D:\idea-project\Java-Virtual-Machine\01-chapter\src\main\java\cn\wickson\jvm\item01>javac Calculator.java

D:\idea-project\Java-Virtual-Machine\01-chapter\src\main\java\cn\wickson\jvm\item01>dir /a /w
...
Calculator.class Calculator.java

image-20240228223233468

2.2. 通过 jclasslib 获取

jclasslib:这个是 Github 上开发的一款查看字节码的插件。

GIthubhttps://github.com/ingokegel/jclasslib

Idea 插件:Plugins —> Marketplace —> jclasslib

  • Windows 本地展示

image-20240228224134386

  • Idea 插件展示

image-20240228225031165

3. 字节码组成部分

通过上面 jclasslib 的插件信息,我们可以看到字节码信息分为如下 6 个部分:

  • 基本信息
  • 常量池
  • 接口
  • 字段
  • 方法
  • 属性

3.1. 基本信息

基本信息:主要包含 魔数、字节码文件对应的 java 版本号、访问标识、父类和接口。

  • 魔数:字节码文件的头 4 个字节,是一个固定的值:ca fe ba be

  • 主副版本号:主副版本号指的是编译字节码文件的 JDK 版本号,主要的作用是判断当前字节码的版本和运行时的 JDK 是否兼容。

3.2. 常量池

常量池:常量池是一组常量的集合,包括字面值常量、符号引用、类和接口名等。

3.3. 字段

字段表(Field Table):描述类的字段,包括字段名称、类型、访问修饰符等。

3.4. 方法

方法表(Method Table):描述类的方法,包括方法名称、参数列表、返回类型、访问修饰符等。

image-20240228231520318

  • 对应的 java 代码
1
2
3
public void add(int a, int b) {
this.result = a + b;
}
  • 对应字节码信息
字节码 指令 注释
0 aload_0 将对象引用(this)加载到操作数栈
1 iload_1 将第一个整数型本地变量加载到操作数栈,对应 int a
2 iload_2 将第二个整数型本地变量加载到操作数栈,对应 int b
3 iadd 将操作数栈顶的两个整数相加,并将结果压入操作数栈,对应 a + b
4 putfield #2 将操作数栈顶的整数值存储到Calculator类的result字段中,对应 this.result =
7 return 返回方法

3.5. 属性

属性表(Attribute Table):包含了各种附加信息,如代码行号、异常处理器、注解等。

4. 阿里 Arthas

官网地址:https://arthas.aliyun.com

Arthas 是一款线上监控诊断产品,通过全局视角实时查看应用 load、内存、gc、线程的状态信息,并能在不修改应用代码的情况下,对业务问题进行诊断,包括查看方法调用的出入参、异常,监测方法执行耗时,类加载信息等,大大提升线上问题排查效率。

4.1. Arthas 安装&启动

下载地址:https://github.com/alibaba/arthas

  • 本次下载的是 Windows arthas-all-3.7.2 版本

image-20240229225538435

  • 我们启动我们本次运行的程序 ArthasDemo.java

image-20240229230745211

  • 启动 Arthas , 可以看到 [6] 就是我们本次启动的程序
1
2
3
4
5
6
7
8
9
10
11
12
D:\Software\Arthas>java -jar arthas-boot.jar
[INFO] JAVA_HOME: D:\Software\Java\jre1.8.0_351
[INFO] arthas-boot version: 3.7.2
[INFO] Process 7656 already using port 3658
[INFO] Process 7656 already using port 8563
[INFO] Found existing java process, please choose one and input the serial number of the process, eg : 1. Then hit ENTER.
* [1]: 7656
[2]: 3440 org.jetbrains.idea.maven.server.RemoteMavenServer36
[3]: 14692 org.jetbrains.jps.cmdline.Launcher
[4]: 7652 org.jetbrains.idea.maven.server.RemoteMavenServer36
[5]: 8696
[6]: 10780 cn.wickson.jvm.item02.ArthasDemo

4.2. Arthas 相关命令

4.2.1. 查看 DashBoard

1
2
# 我们通过如下命令可以看到三块区域信息
[arthas@15660]$ dashboard -i 2000 -n 1
ID NAME GROUP PRIORITY STATE CPU% DELTA_TIME TIME INTERRUPTED DAEMON
线程ID 线程名 线程组名 线程优先级 线程状态 线程的cpu使用率 线程运行增量CPU时间 总时间 中断状态 是否守护线程

image-20240229232245189

Memory used total usage GC
内存区域 内存使用量 内存最大值 内存使用率 GC

image-20240229232350893

当前操作系统运行信息

image-20240229232502766

4.2.2. 反编译字节码

1
2
# 我们可以通过 jad 命令反编译出源码信息
[arthas@15660]$ jad cn.wickson.jvm.item02.ArthasDemo

image-20240229232740814