Skip to content

类加载

[[Klass指针和Mark Word]]

在 Java 虚拟机(JVM,基于 HotSpot 实现)中,.class 文件的加载过程涉及将类的字节码加载到内存中,并将其转换为 JVM 内部可用的数据结构。以下是 .class 文件加载位置及过程的清晰说明:

.class 文件加载到哪里?

.class 文件在加载时,其内容主要被存储在 方法区(Method Area)(JDK 1.8 之前)或 元空间(Metaspace)(JDK 1.8 及之后)。具体来说:

  1. 存储位置

    • 方法区/元空间.class 文件的字节码被解析后,转换为 JVM 内部的运行时数据结构,存储在方法区(JDK 1.7 及之前称为永久代,PermGen)或元空间(JDK 1.8 及之后)。这些数据包括:
      • 类的元数据(如类名、父类、接口、方法表、字段表等)。
      • 常量池(包含字面量、符号引用等)。
      • 静态变量(类变量)。
      • 即时编译器(JIT)编译后的代码缓存。
    • 元空间的特点(JDK 1.8 及之后):
      • 元空间使用本地内存(Native Memory),而不是 JVM 堆内存,因此不再受限于 -XX:MaxPermSize 参数,而是由系统可用内存决定。
      • 元空间由 JVM 的元空间虚拟机管理,采用组块分配(chunk allocation)方式,动态分配和回收内存。
    • 加载过程
      根据 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 开始,字符串常量池和静态变量移至堆)。