深浅模式
类的加载过程
更新: 1/23/2026 字数: 0 字
1、从磁盘上的 .java 源代码到内存中鲜活的 Object,是一个跨越编译期和运行期的过程。我们可以将其拆解为四个核心阶段
阶段一:编译期(Source to Bytecode)
在项目启动之前,首先要将人类可读的代码转化为 JVM 能理解的指令。
词法/语法分析: javac 编译器检查你的代码是否符合 Java 语法。
符号表填充: 记录类名、变量名、方法名。
生成字节码: 最终产出 .class 文件。这个文件包含了常量池、方法表、字段表以及最重要的指令流。
阶段二:类加载过程(Loading & Linking)
当你执行 java -jar 启动项目时,JVM 会寻找主类(Main Class)并触发加载。
加载 (Loading) 通过**类加载器(ClassLoader)**将 .class 文件的二进制流读入内存,并在 方法区(Method Area/Metaspace) 创建对应的 Class 对象。
链接 (Linking) 这个阶段分三步,确保代码能安全运行:
验证 (Verification): 检查字节码是否合法,会不会破坏 JVM 安全(比如有没有越界跳转)。
准备 (Preparation): 为静态变量分配内存并赋初始零值(如 int 设为 0,Object 设为 null)。注意此时还没执行你的赋值逻辑。
解析 (Resolution): 将常量池内的符号引用(比如方法名字符串)替换为直接引用(内存地址指针)。
- 初始化 (Initialization) 这是你上一条提问中提到的关键环节。JVM 执行
<clinit>方法,真正开始运行你的静态代码块(static {})和静态变量赋值逻辑。此处有 JVM 锁保证线程安全。
阶段三:运行时内存布局(Runtime Data Areas)
类加载完成后,JVM 的内存空间已经各就各位,准备为对象分配地盘:
方法区 (Metaspace): 存放类的结构信息(常量池、字段、方法数据)。
堆 (Heap): 绝大多数对象“出生”的地方,也是垃圾回收的主战场。
栈 (Stack): 每个线程私有。每调用一个方法就会压入一个“栈帧”,存放局部变量。
程序计数器 (PC): 记录当前线程执行到哪一行字节码了。
阶段四:创建对象(Object Instantiation)
当代码执行到 new User() 时,真正的“造物”过程开始:
类加载检查: JVM 先看 User 类加载过没有。如果没有,重复阶段二。
分配内存:
根据类信息确定对象大小。
在堆中划出一块空间。
并发安全: 使用 TLAB (Thread Local Allocation Buffer),每个线程先在自己私有的缓冲区分配,避免多线程抢地盘。
初始化零值: 将内存空间初始化为零(保证了对象实例变量不赋值也能用,因为有默认值)。
设置对象头: 在对象头上打上标记(Mark Word),记录它是哪个类的实例、哈希码、GC 分代年龄、锁状态等。
执行构造方法 (
<init>): 按照你的代码逻辑,执行构造函数,进行真正的属性赋值。
总结:从磁盘到内存的链条
磁盘: User.class 文件。
方法区: 加载类的“模版”信息。
栈: 存放引用(Reference),就像遥控器。
堆: 存放真正的对象实例,就像电视机。
举个例子: > 栈里的 User user 只是一个 4 字节或 8 字节的地址,它指向堆中那块巨大的 User 对象内存。
2、简单的 User 类作为示例,然后看它在 JVM 运行时的各个内存区域是如何分布的
java
public class User {
// 静态变量(类变量)
public static String group = "Admin";
// 实例变量
private String name;
private int age;
public User(String name, int age) {
this.name = name;
this.age = age;
}
public void sayHello() {
// 局部变量
int temp = 10;
System.out.println("Hello, " + name);
}
}
// 启动代码
User user = new User("Alice", 25);
user.sayHello();视觉化布局描述
如果我们用一种更形象的方式来描述 User user = new User("Alice", 25) 这一行代码:
1、在栈(Stack)里: 你会看到一个名为 user 的小格子,里面存着一串十六进制数字(例如 0x1234),这就像是一把遥控器。
2、在堆(Heap)里: 在地址 0x1234 的位置,躺着一块肥沃的土地。
对象头:标记着它是 User 类,还有它的哈希码、锁状态。
实例数据:这里存着 age = 25。至于 name,它又是一个“子遥控器”,指向堆中另一块存着 "Alice" 字符数组的区域。
3、在元空间(Metaspace)里: 这里是 “图纸库”。
- 它记录了 User 类有哪些方法(sayHello)、哪些字段。
这里的 group 变量就像是一个公共告示牌,所有 User 实例都能看到它写着 "Admin"。
总结
栈是“动作”:负责方法调用和局部变量(快、私有)。
堆是“工厂”:负责生产和存放对象实体(大、共享)。
元空间是“规格”:负责存放类的模版信息(稳、持久)
text
绘制了一张详细的 JVM 内存布局图。这张图展示了执行 User user = new User("Alice", 25); 时,数据是如何在各区域分布并相互连接的;
线程私有区域 (Thread Local) | 线程共享区域 (Shared)
========================================== | ==========================================
|
【虚拟机栈 Stack】 (线程A) | 【堆 Heap】 (对象实例)
+------------------------------+ | +---------------------------------------+
| sayHello() 方法栈帧 | | | |
| +--------------------------+ | | | +-------------------------------+ |
| | 局部变量表: | | | | | User 对象实例 (0x1234) | |
| | [0] this (指向堆0x1234) --|-------------|--->| +---------------------------+ | |
| | [1] temp = 10 | | | | | [对象头] Mark Word / 类指针 |---|---|--+
| +--------------------------+ | | | +---------------------------+ | | |
+------------------------------+ | | | [实例数据] age = 25 | | | |
| main() 方法栈帧 | | | | [实例数据] name (指向"Alice")|---|---|--+
| +--------------------------+ | | | +---------------------------+ | | | |
| | user变量 (指向堆0x1234)---|-------------|--->| | | | |
| +--------------------------+ | | +---------------------------------------+ |
+------------------------------+ | | |
| v |
【程序计数器 PC】 | +---------------------------------------+ |
+------------------------------+ | | String "Alice" (对象/数组) | |
| 当前指令: 0x0021 (sayHello) | | +---------------------------------------+ |
+------------------------------+ | |
| |
========================================== | ==========================================
|
| 【元空间 Metaspace】 (本地内存)
| +---------------------------------------+
| | |
| | +-------------------------------+ |
| | | User 类元信息 (模版) |<--+
| | +-------------------------------+ |
| | | 方法数据 (sayHello代码) | |
| | | 静态变量: group = "Admin" | |
| | | 常量池: "Hello, " | |
| | +-------------------------------+ |
| | |
| +---------------------------------------+