【JVM系列笔记】字节码

本文涉及的产品
云数据库 Tair(兼容Redis),内存型 2GB
Redis 开源版,标准版 2GB
推荐场景:
搭建游戏排行榜
RDS MySQL Serverless 基础系列,0.5-2RCU 50GB
简介: 本文介绍了Java虚拟机(JVM)的组成,包括类加载子系统、运行时数据区、执行引擎和本地接口。字节码文件由基础信息(如魔数和版本号)、常量池、字段、方法和属性组成。常量池用于存储字符串等共享信息,方法区则包含字节码指令。执行引擎包含解释器、即时编译器和垃圾回收器,负责字节码的解释和优化。文章还提到了字节码工具,如javap、jclasslib和Arthas,用于查看和分析字节码。

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

(待补充)

目录
相关文章
|
6月前
|
安全 Java
对 JVM 的类加载机制以及寻找字节码文件的“双亲委派模型”的理解
对 JVM 的类加载机制以及寻找字节码文件的“双亲委派模型”的理解
39 0
|
5月前
|
存储 算法 Java
技术笔记:JVM的垃圾回收机制总结(垃圾收集、回收算法、垃圾回收器)
技术笔记:JVM的垃圾回收机制总结(垃圾收集、回收算法、垃圾回收器)
57 1
|
5月前
|
存储 Java 编译器
JVM系列7-虚拟机字节码执行引擎
JVM系列7-虚拟机字节码执行引擎
29 1
|
6月前
|
Java 索引
【JVM】字节码文件的组成部分
【JVM】字节码文件的组成部分
54 1
|
6月前
|
存储 Java 程序员
【JVM系列笔记】类生命周期
类的生命周期包括加载、连接(验证、准备、解析)、初始化、使用和卸载五个阶段。加载时,类加载器根据全限定名获取字节码,然后在方法区中创建InstanceKlass对象,并在堆上生成对应的Class对象。连接阶段验证字节码的正确性,准备阶段为静态变量分配内存并赋初始值,解析阶段将符号引用转换为直接引用。初始化阶段执行clinit方法,如静态变量赋值和静态代码块。类的初始化在访问静态成员、使用Class.forName、创建类实例或其子类时触发。
90 1
|
6月前
|
存储 Java 索引
深入浅出JVM(十)之字节码指令(下篇)
深入浅出JVM(十)之字节码指令(下篇)
|
6月前
|
存储 Java 索引
深入浅出JVM(九)之字节码指令(上篇)
深入浅出JVM(九)之字节码指令(上篇)
|
6月前
|
存储 XML 监控
JVM工作原理与实战(三):字节码文件的组成
JVM作为Java程序的运行环境,其负责解释和执行字节码,管理内存,确保安全,支持多线程和提供性能监控工具,以及确保程序的跨平台运行。本文主要介绍了字节码文件的基础信息、常量池、方法、字段、属性等内容。
93 6
|
6月前
|
前端开发 Java 应用服务中间件
【JVM系列笔记】类加载
类加载器分为两类,一类是Java代码中实现的,一类是Java虚拟机底层源码实现的。常见的类加载器有启动类加载器,拓展类加载器,应用类加载器以及自定义类加载器。以及类加载机制,双亲委托策略,以及打破双亲委托策略的几种方式。
83 0
|
6月前
|
监控 数据可视化 安全
JVM工作原理与实战(二):字节码编辑器jclasslib
JVM作为Java程序的运行环境,其负责解释和执行字节码,管理内存,确保安全,支持多线程和提供性能监控工具,以及确保程序的跨平台运行。本文主要介绍了字节码编辑器jclasslib的安装和使用等内容。
174 4