【JVM极简教程】2小时快速学会JVM,史上用时最短,效率最高!_哔哩哔哩_bilibili
一.JVM跨平台的原理
我们的开发者在不同的操作系统上都开发了相关的JVM,都可以去编译字节码。本质跟QQ,WX,BiliBili等软件是一样的,都是运行在操作系统上的软件。

二.字节码的作用是什么
2.1编译后的字节码文件是2进制,只是展示的时候为16进制展示

- .class 字节码文件 = 二进制文件
- 我们看到的 16 进制,只是它的展示形式,不是文件本身
- JVM 读取这个二进制字节码,再翻译成当前系统 CPU 能识别的机器码(二进制)
2.2字节码可以加快JVM翻译的速度
1.字节码是二进制码,交给 JVM 后,JVM 翻译速度更快。
如果直接交 .java 给 JVM,就变成跟 Python 一样的解释型语言,翻译时间变长,速度更慢!

2.兼容多钟语言,在多种环境上运行

三.整体结构
3.1整体简介

Hello.java → 编译为 Hello.class(字节码)→ 类加载子系统 加载 → 放入 运行时数据区 → 执行引擎 执行。
1. 类加载子系统
- 负责加载、验证、准备、解析、初始化
.class字节码文件 - 把类的信息加载到方法区
2. 运行时数据区(核心内存区域)
- 程序计数器(PC 寄存器) :记录当前线程执行到哪条字节码指令,线程私有
- Java 方法栈:存储 Java 方法的局部变量、操作数栈、方法出口等,线程私有
- 本地方法栈 :存储
native本地方法的调用信息,线程私有 - 方法区:存储类的元数据(类结构、常量池、静态变量等),所有线程共享
- 堆:存储对象实例和数组,所有线程共享,是垃圾回收的主要区域
3. 执行引擎
- 解释器:逐行解释字节码为机器码,启动快、执行慢
- JIT 编译器 :将热点代码编译为机器码缓存,后续直接执行,提升运行效率
- 垃圾回收器(GC) :自动回收堆中不再使用的对象,避免内存泄漏
4. 本地方法
- 调用非 Java 实现的底层native方法(如 C/C++),与操作系统交互
3.2类加载子系统的作用是什么

1. 加载(Loading)
- 从
Hello.class字节码文件中,读取类的二进制数据 - 在内存中生成一个代表这个类的
Class对象 - 把类的结构信息存入方法区
2. 链接(Linking)
链接又细分为 3 步:
① 验证(Verification)
- 检查
.class文件是否符合 JVM 规范 - 比如:验证文件格式(是否以
cafebabe开头)、语法合法性、类型安全等 - 目的:防止恶意或错误的字节码危害 JVM 安全
② 准备(Preparation)
- 为类中的 static 变量 分配内存,并设置默认零值
- 例:
static int a = 10;→ 这里先给a分配内存,赋值为0,不是10
- 例:
- 不涉及实例变量,实例变量是在对象创建时分配到堆里的
③ 解析(Resolution)
- 将类、接口、字段、方法等的符号引用(比如字符串形式的类名)
- 替换为直接引用(内存地址指针)
- 让 JVM 能直接定位到目标内存位置,方便后续执行
3. 初始化(Initialization)(类加载的最后一步)
- 真正执行类的初始化逻辑:
- 执行
static代码块 - 给
static变量赋用户定义的初始值- 例:
static int a = 10;→ 这里才把a从0改成10
- 例:
- 执行
- 这是类加载的最后一步,也是真正执行程序员写的代码的地方
- 根据包名类名找到方法区中的klass对象的地址
3.3类加载器的分类以及怎么工作的
1.分类
JDK提供给我们的:
BootStrapClassLoader类:
- 作用:加载 JRE/lib 目录下的核心类
- 加载什么:
rt.jar(String、Integer、Thread 等 Java 核心类) - 特点:没有父加载器
- 一句话:负责加载 Java 最核心的基础类
ExtClassLoader类:
- 作用:加载 JRE/lib/ext 目录下的扩展类
- 加载什么:Java 的扩展 API、加密、安全相关类
- 父加载器:BootStrapClassLoader
- 一句话:加载 $JAVA_HOME/jre/lib/ext下的扩展 jar 包(包括原来有的和自己手动添加进去的)

AppClassLoader类:
- 作用:加载 我们项目 classpath 下的类
- 加载什么:你写的所有
.java编译后的类 - 父加载器:ExtClassLoader
- 一句话:加载我们自己写的代码!
不是JDK提供给我们的:
WebAppClassLoader
WebAppClassLoader 是 Tomcat 专用的类加载器,负责加载当前 Web 项目里的类和 jar 包,让多个项目之间互相隔离,互不干扰,并且打破双亲委派,优先加载自己项目的类。
先自己加载 → 加载不到才问爸爸(AppClassLoader)
为什么?因为它要优先加载 自己项目里的 jar 包,而不是用全局的!
2.双亲委派(必背!)
类加载顺序: App → Ext → BootStrap(从下往上找)
加载顺序: BootStrap → Ext → App(从上往下加载)
目的:安全!防止别人篡改 Java 核心类!
java
// 类加载器的 loadClass 方法
public Class<?> loadClass(String name) {
// 1. 先看有没有已经加载过
if (已加载) return 类;
// 2. 【关键点】无论如何,先递归问父加载器!
if (父加载器 != null) {
return 父加载器.loadClass(name); // ← 递归往上
}
// 3. 到了顶层 Bootstrap 都没有,才自己找
return findClass(name);
}
- 一路递归往上
- 先到 Bootstrap
- Bootstrap 找不到 → 递归退出
- 回到 Ext 找
- Ext 找不到 → 回到 App 找
