【JVM】面试题-元空间的内部结构


元空间的内部结构

在《深入理解Java虚拟机》一书中,对元空间(Metaspace)的描述是:

它用于存储类的元数据,包括已被虚拟机加载的类信息、成员变量、方法信息、运行时常量池、静态变量、即时编译器编译后的代码缓存等。

复制代码
======= 🌟 青柠来相伴,代码更简单。🌟 =======
📚 本文所有内容,我都整理在了 青柠合集 里。👇
🎯 搜索关注【青柠代码录】,即可查看所有合集文章 ~
======= 🌟 ================ 🌟 =======

一、类信息

对于每一个被加载的类型(类 class、接口 interface、枚举 enum、注解 annotation),JVM 必须在元空间中,存储以下信息:

  1. 全限定名:类型的完整有效名称(包名.类名)。
  2. 父类信息 :直接父类的完整有效名(java.lang.Object 和接口没有父类)。
  3. 修饰符 :如 publicabstractfinal 等。
  4. 接口列表:该类直接实现的所有接口的有序列表。

二、成员变量

JVM 必须保存类型中所有成员变量 的相关信息,以及它们的声明顺序

  • 信息明细:包括变量的名称、类型、修饰符。

补充说明:这里的修饰符包括 publicprivateprotectedstaticfinalvolatiletransient 等。

三、方法信息

方法信息是元空间中的重头戏,JVM 必须保存以下细节(同样包含声明顺序):

  • 基本信息 :方法名称、返回类型(或 void)、参数的数量与类型、修饰符。
  • 字节码指令 :方法的字节码(bytecodes)、操作数栈大小、局部变量表大小(抽象方法和本地方法除外)。
  • 异常表:每一个异常处理的开始位置、结束位置、在程序计数器中的偏移地址,以及被捕获的异常类的常量池索引。

四、静态变量(non-final)与全局常量(static final)

这是一个非常重要的知识点,也是面试中经常考察的地方。

1、普通静态变量

静态变量与类关联在一起,随着类的加载而加载。它们被类的所有实例所共享,即使没有类实例,你也可以直接访问。

为了证明这一点,我们来看一段代码:

复制代码
public class MethodAreaTest {
    public static void main(String[] args) {
        Order order = null; // 这里是个 null 引用
        order.hello();      // 不会报空指针异常!
        System.out.println(order.count);
    }
}

class Order {
    public static int count = 1;      // 普通静态变量
    public static final int number = 2; // 全局常量

    public static void hello() {
        System.out.println("hello!");
    }
}

运行结果

复制代码
hello!
1

原因static 方法和属性属于类,而不属于某个具体的对象实例。所以即使 ordernull,JVM 依然能通过类信息,找到对应的属性和方法。

2、全局常量(static final)

static final 修饰的变量处理方式不同。这类常量在编译期就被确定,并放入常量池中。

3、字节码验证

理论说完了,我们用 javap 命令来验证一下上面的结论。

  1. 找到 Order.class 字节码文件,右键 -> Open in Terminal
  2. 执行命令:javap -v -p Order.class > tst.txt(反编译并输出到文本)。

打开生成的 tst.txt,可以看到如下关键信息:

复制代码
public static int count;
    descriptor: I
    flags: ACC_PUBLIC, ACC_STATIC
    // 注意:这里没有 ConstantValue,说明 count 是在类加载的 <clinit> 阶段赋值的

public static final int number;
    descriptor: I
    flags: ACC_PUBLIC, ACC_STATIC, ACC_FINAL
    ConstantValue: int 2   // 编译期就已经确定了值!

分析结论

  • 对于 static final 修饰的常量 number,编译时就直接把 2 赋值给了它(体现在 ConstantValue 属性中)。
  • 对于普通的 static 变量 count,字节码中没有 ConstantValue,它是在类加载的准备阶段 赋默认零值,在初始化阶段赋真实值。

五、常量池

具体内容见常量池文档。

六、元空间存储结构总览

为了方便大家记忆,这里画了一个简单的逻辑图(文字版):

存储区域 主要内容
类型信息 类全限定名、父类、修饰符、接口列表
字段信息 字段名、类型、修饰符、声明顺序
方法信息 方法名、返回值、参数、修饰符、字节码、操作数栈、异常表
常量池 存放编译期生成的各种字面量和符号引用(具体内容见常量池专项解析)
静态变量 类的所有实例共享,属于类级别
JIT 代码缓存 即时编译器(Just-In-Time Compiler)编译后的本地机器码,存放在元空间的代码缓存区中(这部分也是元空间区别于永久代的重要特性)
相关推荐
两年半的个人练习生^_^3 小时前
JVM 内存结构详解
java·jvm
番茄去哪了3 小时前
类的生命周期
jvm
m0_702036533 小时前
如何通过SQL视图对比两表差异_利用FULL JOIN构建视图
jvm·数据库·python
老纪4 小时前
golang如何实现工作流引擎_golang工作流引擎实现要点
jvm·数据库·python
青云计划4 小时前
JVM从入门到精通
java·jvm
Dicky-_-zhang4 小时前
分布式缓存实战:Redis与多级缓存架构的完整指南
java·jvm
Devin~Y4 小时前
大厂Java面试实录:Spring Boot/Cloud、JVM、Redis、Kafka、MyBatis 到 RAG/Agent 的三轮连环问(含答案详解)
java·jvm·spring boot·redis·spring cloud·kafka·mybatis
2401_850491654 小时前
Bootstrap和OpenLayers结合开发的示例
jvm·数据库·python
AI人工智能+电脑小能手4 小时前
【大白话说Java面试题 第60题】【JVM篇】第20题:垃圾收集算法和垃圾收集器有什么区别?
java·jvm·算法·面试