文章目录
- [0. 什么是字节码文件](#0. 什么是字节码文件)
- [1. 打开字节码文件](#1. 打开字节码文件)
- [2. 字节码文件的组成](#2. 字节码文件的组成)
-
- [2.1 一般信息 ⭐](#2.1 一般信息 ⭐)
-
- [魔数 Magic ⭐](#魔数 Magic ⭐)
- 主次版本号
- [2.2 常量池 ⭐](#2.2 常量池 ⭐)
- [2.3 方法 ⭐](#2.3 方法 ⭐)
- [3. 字节码常用工具](#3. 字节码常用工具)
-
- [3.1 javap](#3.1 javap)
- [3.2 jclasslib插件](#3.2 jclasslib插件)
- [3.3 阿里Arthas](#3.3 阿里Arthas)
-
- 常用命令
-
- [① dashboard](#① dashboard)
- [② dump](#② dump)
- [③ jad](#③ jad)
- 总结
0. 什么是字节码文件
字节码文件是一种介于源代码和机器码之间的二进制中间代码文件,用于在虚拟机上执行程序。
jvm不关心运行在内部的是什么语言编写的,只关心字节码

要想使得Java文件在jvm中正确运行,就需要转为字节码文件。
类比理解

1. 打开字节码文件
使用Notepad++的十六进制插件查看.class文件,先安装HEX Editor插件:

然后用插件打开.class文件。
插件 -> HEX Editor -> View in HEX

可以看到:

其中,左边表示当前文件中的地址,中间是十六进制数据,最后是编码后的结果。编译后的结果显示乱码,无法直观的查看到字节码文件。就需要使用工具来查看,比如jclasslib。

使用工具jclasslib(下载地址:https://github.com/ingokegel/jclasslib/releases),打开target目录下的`.class`文件,可以看到:

2. 字节码文件的组成
使用工具jclasslib打开target目录下的.class文件,可以看到:

- 一般信息
- 常量池
- 接口
- 字段
- 方法
- 属性
下方重点介绍一般信息、常量池、方法。
2.1 一般信息 ⭐
可以看到信息概览。

魔数 Magic ⭐
java字节码文件中,将文件头称为魔数 Magic。class文件开头4个字节固定为cafebabe。
- 作用:jvm可以通过文件头可以判断是否是一个合法的class文件。因为文件的扩展名是可以修改的,比如png可以改成avi,通过文件头可以看到原始文件类型。

因此,我们通过软件去打开文件时,软件会校验文件头来获取类型,如果不支持,就会报错。
其他的文件类型对应的文件头:

主次版本号
指class由哪个版本Java编译。主版本号用来标识大版本号,jdk1.2之后每升级一个大版本就+1。主版本号减去44就是jdk的版本号,比如61-44=17,jdk就是17。

2.2 常量池 ⭐
- 作用:避免相同内容,重复定义,节省空间。
- 常量池中的数据都有一个编号,从1开始。通过编号可以快速找到对应的数据。


2.3 方法 ⭐
存储该方法的所有元数据定义,以及供 Java 虚拟机(JVM)实际执行的指令序列(运行逻辑)。
以下方代码为例:
java
public void test07(){
int i = 0;
i = i++;
System.out.println(i);
}
用jclasslib打开对应的字节码文件:

通过右击指令名,可以显示JVM规范,也就是该指令在jvm中的含义。

其中,
iconst_<i>表示:将int常量i放到操作数栈中。iconst_0也就表示将常量0放到操作数栈中。

istore_<n>表示:操作数栈出栈,在局部变量表的索引为n的地方设置该值。那么istore_1表示,将前一步入栈的常量0出栈,放到局部变量表下表为1的地方。

iload_<n>表示:将局部变量表中下标为n的值入栈操作数栈。那么iload_1则表示将常量表中下标为1的值也就是0,放到操作数栈。(注意:入栈不影响常量表中的值)

iinc表示:将局部变量表中索引下标中的值增加。那么iinc 1 by 1表示将常量表下标为1的值增加1。

那么,整个字节码可以解释为:
0 将常量0放到操作数栈中。stacktop=0
1 将常量0出栈,放到局部变量表下表为1的地方。local1=0
2 将常量表中下标为1的值,放到操作数栈。stacktop=0
3 将常量表下标为1的值增加1。local1=1
6 将常量0出栈,放到局部变量表下表为1的地方。local1=0
10 将常量表中下标为1的值,放到操作数栈。stacktop=0
注意:局部变量表不能直接运算,必须放到操作数栈中。

综上,常量表下标为1的值为0,也就是说i的值为0。
3. 字节码常用工具
3.1 javap
是JDK自带的反编译工具,可以通过控制台查看字节码文件的内容。适合在服务器上查看字节码文件内容。
-
检查javap命令是否可用:
一般安装了java环境就会有

-
这里以为jar包为例,先使用命令
jar -xvf xx.jar将jar包解压:
-
解压后字节码文件全部存放在BOOT-INF中。

-
查看某个字节码文件的信息,并保存在.txt文件:
javap -v 地址\xx.class > 地址\xx.txt

得到包含所有完整字节码内容的文件

3.2 jclasslib插件
idea中有jclasslib插件,可以通过该插件在代码编译后实时查看字节码内容。

View->Show Bytecode With Jclasslib 可以查看到对应的字节码文件。(注意一定要先选中要查看字节码文件的源代码,否则不会出现这个选项)

右侧可以看到对应的字节码文件信息

注意:如果源代码内容发生改变后,需要先编译才能看到最新的字节码文件。

点击刷新

以上两款工具都是针对本地或者服务器上静态查看字节码文件,如果程序在运行了要怎么查看类的字节码信息?
3.3 阿里Arthas
Arthas是阿里巴巴开源的 Java 在线诊断工具,主要用于生产环境排查 Java 应用问题,能够实时查看应用load、内存、gc、线程的状态信息。
官方文档:https://arthas.aliyun.com/doc
- 下载安装包:

- 解压:

- 启动arthas:
可以看到所有在运行中的程序

- 查看指定程序,输入编号,这里输入1为例:

常用命令
① dashboard
查看 JVM 总览:


这里执行dashboard -i 2000 -n 1,即每2秒刷新一次,刷新次数为一次,可以看到如下效果:

可以看到程序状态、CPU占有率、内存占用、GC、操作系统、java版本、CPU核数等等
② dump
把 JVM 中已经加载的某个类的字节码文件导出到本地磁盘。
执行命令:dump -d "D:\test\jvm\data" com.example.utils.UtilsApplication

可以查看到生成的字节码文件

③ jad
将运行中的类的字节码信息反编译为源码。通过该命令可以确认源代码是不是最新的。
通过jad 类名命令拿到源代码,这里以jad com.example.utils.UtilsApplication为例:

总结
- 打开字节码文件方式:jclasslib、javap命令、idea插件、arthas
- 其中arthas可以用于查看运行时的类的字节码信息,可以通过jad命令拿到反编译的源码,可以用于处理线上问题。
以上为个人学习分享,如有问题,欢迎指出:)