类加载
[[Klass指针和Mark Word]]
在 Java 虚拟机(JVM,基于 HotSpot 实现)中,.class 文件的加载过程涉及将类的字节码加载到内存中,并将其转换为 JVM 内部可用的数据结构。以下是 .class 文件加载位置及过程的清晰说明:
.class 文件加载到哪里?¶
.class 文件在加载时,其内容主要被存储在 方法区(Method Area)(JDK 1.8 之前)或 元空间(Metaspace)(JDK 1.8 及之后)。具体来说:
-
存储位置:
- 方法区/元空间:
.class文件的字节码被解析后,转换为 JVM 内部的运行时数据结构,存储在方法区(JDK 1.7 及之前称为永久代,PermGen)或元空间(JDK 1.8 及之后)。这些数据包括:- 类的元数据(如类名、父类、接口、方法表、字段表等)。
- 常量池(包含字面量、符号引用等)。
- 静态变量(类变量)。
- 即时编译器(JIT)编译后的代码缓存。
- 元空间的特点(JDK 1.8 及之后):
- 元空间使用本地内存(Native Memory),而不是 JVM 堆内存,因此不再受限于
-XX:MaxPermSize参数,而是由系统可用内存决定。 - 元空间由 JVM 的元空间虚拟机管理,采用组块分配(chunk allocation)方式,动态分配和回收内存。
- 元空间使用本地内存(Native Memory),而不是 JVM 堆内存,因此不再受限于
-
加载过程:
根据 JVM 规范,.class文件加载是类加载过程的第一步(Loading),主要包括以下步骤: -
获取字节流:JVM 通过类加载器(如 Bootstrap ClassLoader 或自定义类加载器)读取
.class文件的二进制字节流(可以来自文件系统、JAR 文件、网络等)。 - 转换数据结构:将字节流代表的静态存储结构(即
.class文件格式)转换为方法区/元空间的运行时数据结构,生成一个 Klass 对象(JVM 内部的 C++ 对象,用于表示类的元数据)。 - 创建 Class 对象:在堆内存中生成一个
java.lang.Class实例,作为方法区/元空间中类数据的访问入口。这个Class对象存储在 Java 堆中,供 Java 代码通过反射访问。 -
内存布局:
-
方法区/元空间:存储类的元数据(Klass 对象)、常量池、静态变量等。
- 堆内存:存储
java.lang.Class实例,堆中的每个对象通过对象头的 Klass 指针 关联到方法区/元空间中的 Klass 对象。 - 运行时常量池:
.class文件中的常量池(Constant Pool)会被解析为运行时常量池,存储在方法区/元空间(JDK 1.7 及之前)或部分迁移到堆内存(JDK 1.7 开始,字符串常量池和静态变量移至堆)。
- 方法区/元空间: