字节码文件
字节码文件
字节码文件是指一种中间代码格式,它通常是被编译后的程序代码,以便于在虚拟机或特定运行环境中执行。字节码的主要目的是实现跨平台性和提高执行效率。
字节码的优点包括
- 平台独立性:字节码可以在任何支持相应虚拟机的操作系统上运行。
- 安全性:在虚拟机中运行的字节码可以提供沙箱安全性,限制代码的执行权限。
- 动态加载:字节码可以在运行时动态加载,允许更灵活的程序架构。
字节码文件的组成
- 基础信息:魔数、字节码文件对应的Java版本号、访问标识(public final等等)、父类和接口信息
- 常量池:保存了字符串常量、类或接口名、字段名,主要在字节码指令中使用
- 字段: 当前类或接口声明的字段信息
- 方法: 当前类或接口声明的方法信息,核心内容为方法的字节码指令
- 属性: 类的属性,比如源码的文件名、内部类的列表等
1、基础信息
基本信息包含了jclasslib中能看到的两块内容一般信息和接口:
Magic魔数
每个Java字节码文件的前四个字节是固定的,用16进制表示就是0xcafebabe。文件是无法通过文件扩展名来确定文件类型的,文件扩展名可以随意修改不影响文件的内容。软件会使用文件的头几个字节(文件头)去校验文件的类型,如果软件不支持该种类型就会出错。
比如常见的文件格式校验方式如下:
Java字节码文件中,将文件头称为magic魔数。Java虚拟机会校验字节码文件的前四个字节是不是0xcafebabe,如果不是,该字节码文件就无法正常使用,Java虚拟机会抛出对应的错误。
主副版本号
主副版本号指的是编译字节码文件时使用的JDK版本号,主版本号用来标识大版本号,JDK1.0-1.1使用了45.0-45.3,JDK1.2是46之后每升级一个大版本就加1;副版本号是当主版本号相同时作为区分不同版本的标识,一般只需要关心主版本号。
JDK1.2之后大版本号计算方法就是 : 主版本号 – 44,比如主版本号52就是JDK8。
版本号的作用主要是判断当前字节码的版本和运行时的JDK是否兼容。如果使用较低版本的JDK去运行较高版本JDK的字节码文件,无法使用会显示如下错误:
有两种方案:
1.升级JDK版本,将图中使用的JDK6升级至JDK8即可正常运行,(容易引发其他的兼容性问题,并且需要大量的测试。)
2.将第三方依赖的版本号降低或者更换依赖,以满足JDK版本的要求。建议使用这种方案
其他基础信息
其他基础信息包括访问标识、类和接口索引
2、 常量池
字节码文件中常量池的作用:避免相同的内容重复定义,节省空间。
比如在代码中,编写了两个相同的字符串“我爱北京天安门”,字节码文件甚至将来在内存中使用时其实只需要保存一份,此时就可以将这个字符串以及字符串里边包含的字面量,放入常量池中以达到节省空间的作用。
String str1 = "我爱北京天安门";
String str2 = "我爱北京天安门";
常量池中的数据都有一个编号,编号从1开始。比如“我爱北京天安门”这个字符串,在常量池中的编号就是7。在字段或者字节码指令中通过编号7可以快速的找到这个字符串。
3、方法
字节码中的方法区域是存放字节码****指令的核心位置,字节码指令的内容存放在方法的Code属性中。
要理解字节码指令是如何执行的,我们需要先理解两块内存区域:操作数栈和局部变量表
操作数栈是用来存放临时数据的内容,是一个栈式的结构,先进后出。
局部变量表是存放方法中的局部变量,包含方法的参数、方法中定义的局部变量,在编译期就已经可以确定方法有多少个局部变量。
字节码指令
1、iconst_n,将常量n放入操作数栈。
2、istore_n,会从操作数栈中,将栈顶的元素弹出来,然后放入局部变量表的n号位置
3、iload_n,将局部变量表n号位置的数据放入操作数栈中
4、iadd,会将操作数栈顶部的两个数据相加
5、iinc n by m,指令指的是将局部变量表n号位置增加m
5、return语句执行,方法结束并返回。
4、字段
字段中存放的是当前类或接口声明的字段信息。
如定义了两个字段a1和a2,这两个字段就会出现在字段这部分内容中。同时还包含字段的名字、描述符(字段的类型)、访问标识(public/private static final等)
5、属性
属性主要指的是类的属性,比如源码的文件名、内部类的列表等。
查看字节码工具
1、文件工具jclasslib idea插件
选择当前文件-》view-》show bytecode with Jclasslib
2、javap命令
javap -v xx.class 文件 文件的全路径名
3、arthas-java应用诊断器
Arthas 是一款线上监控诊断产品,通过全局视角实时查看应用 load、内存、gc、线程的状态信息,并能在不修 改应用代码的情况下,对业务问题进行诊断,大大提升线上问题排查效率。
官网:https://arthas.aliyun.com/doc
arthas-比较重要
快速入门
1. 启动 math-game
java -jar math-game.jar
math-game
是一个简单的程序,每隔一秒生成一个随机数,再执行质因数分解,并打印出分解结果。
2. 启动 arthas
在命令行下面执行(使用和目标进程一致的用户启动,否则可能 attach 失败)
java -jar arthas-boot.jar
执行该程序的用户需要和目标进程具有相同的权限。比如以
admin
用户来执行:sudo su admin && java -jar arthas-boot.jar
或sudo -u admin -EH java -jar arthas-boot.jar
。如果 attach 不上目标进程,可以查看
~/logs/arthas/
目录下的日志。如果下载速度比较慢,可以使用 aliyun 的镜像:
java -jar arthas-boot.jar --repo-mirror aliyun --use-http
java -jar arthas-boot.jar -h
打印更多参数信息。
选择应用 java 进程:
$ $ java -jar arthas-boot.jar
* [1]: 35542
[2]: 71560 math-game.jar
# 选择第二个
通过 jad 来反编译 Main Class
jad 全路径类名