字节码文件

字节码文件

字节码文件是指一种中间代码格式,它通常是被编译后的程序代码,以便于在虚拟机或特定运行环境中执行。字节码的主要目的是实现跨平台性和提高执行效率。

字节码的优点包括

  • 平台独立性:字节码可以在任何支持相应虚拟机的操作系统上运行。
  • 安全性:在虚拟机中运行的字节码可以提供沙箱安全性,限制代码的执行权限。
  • 动态加载:字节码可以在运行时动态加载,允许更灵活的程序架构。

字节码文件的组成

  • 基础信息:魔数、字节码文件对应的Java版本号、访问标识(public final等等)、父类和接口信息
  • 常量池:保存了字符串常量、类或接口名、字段名,主要在字节码指令中使用
  • 字段: 当前类或接口声明的字段信息
  • 方法: 当前类或接口声明的方法信息,核心内容为方法的字节码指令
  • 属性: 类的属性,比如源码的文件名、内部类的列表等

1、基础信息

基本信息包含了jclasslib中能看到的两块内容一般信息和接口

image-20241016154618337

Magic魔数

每个Java字节码文件的前四个字节是固定的,用16进制表示就是0xcafebabe。文件是无法通过文件扩展名来确定文件类型的,文件扩展名可以随意修改不影响文件的内容。软件会使用文件的头几个字节(文件头)去校验文件的类型,如果软件不支持该种类型就会出错。

比如常见的文件格式校验方式如下:

image-20241016154644212

Java字节码文件中,将文件头称为magic魔数。Java虚拟机会校验字节码文件的前四个字节是不是0xcafebabe,如果不是,该字节码文件就无法正常使用,Java虚拟机会抛出对应的错误。

主副版本号

主副版本号指的是编译字节码文件时使用的JDK版本号,主版本号用来标识大版本号,JDK1.0-1.1使用了45.0-45.3,JDK1.2是46之后每升级一个大版本就加1;副版本号是当主版本号相同时作为区分不同版本的标识一般只需要关心主版本号。

JDK1.2之后大版本号计算方法就是 : 主版本号 – 44,比如主版本号52就是JDK8。

image-20241016155157155

版本号的作用主要是判断当前字节码的版本和运行时的JDK是否兼容。如果使用较低版本的JDK去运行较高版本JDK的字节码文件,无法使用会显示如下错误:

image-20241016155040324

有两种方案:

1.升级JDK版本,将图中使用的JDK6升级至JDK8即可正常运行,(容易引发其他的兼容性问题,并且需要大量的测试。)

2.将第三方依赖的版本号降低或者更换依赖,以满足JDK版本的要求。建议使用这种方案

其他基础信息

其他基础信息包括访问标识、类和接口索引

image-20241016155326981

2、 常量池

字节码文件中常量池的作用:避免相同的内容重复定义,节省空间。

比如在代码中,编写了两个相同的字符串“我爱北京天安门”,字节码文件甚至将来在内存中使用时其实只需要保存一份,此时就可以将这个字符串以及字符串里边包含的字面量,放入常量池中以达到节省空间的作用。

String str1 = "我爱北京天安门";
String str2 = "我爱北京天安门";

常量池中的数据都有一个编号,编号从1开始。比如“我爱北京天安门”这个字符串,在常量池中的编号就是7。在字段或者字节码指令中通过编号7可以快速的找到这个字符串。

image-20241016160519128

3、方法

字节码中的方法区域是存放字节码****指令的核心位置,字节码指令的内容存放在方法的Code属性中。

image-20241016160714708

要理解字节码指令是如何执行的,我们需要先理解两块内存区域:操作数栈和局部变量表

操作数栈是用来存放临时数据的内容,是一个栈式的结构,先进后出。

局部变量表是存放方法中的局部变量,包含方法的参数、方法中定义的局部变量,在编译期就已经可以确定方法有多少个局部变量。

字节码指令

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等)

image-20241016170325051

5、属性

属性主要指的是类的属性,比如源码的文件名、内部类的列表等。

image-20241016170402829

查看字节码工具

1、文件工具jclasslib idea插件

选择当前文件-》view-》show bytecode with Jclasslib

image-20241016164422117

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.jarsudo -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 全路径类名

posted @ 2024-11-05 21:10  CH_song  阅读(169)  评论(0)    收藏  举报