JVM--5-深入 JVM 方法区:类的元数据之家

📅 发布时间:2026/7/11 18:56:41 👁️ 浏览次数:
JVM--5-深入 JVM 方法区:类的元数据之家
JVM 第5讲深入 JVM 方法区 —— 类的元数据之家方法区Method Area是 JVM 运行时数据区中非常重要但又经常被误解的一个区域。它主要存储的是已经被虚拟机加载的类信息也被称为“类的元数据之家”。在不同 JDK 版本中方法区的实现发生了很大的变化我们需要分版本来理解。1. 方法区的演变历史重点掌握JDK 版本方法区实现方式是否属于堆内存是否有永久代PermGen实际名称HotSpot是否可动态扩展GC 方式大致JDK 6 及之前永久代PermGen是有Permanent Generation固定大小Full GC 时回收JDK 7永久代部分移出是有但字符串池移到堆Permanent Generation固定大小Full GCJDK 8 及以后元空间Metaspace否无Metaspace动态扩展触发 Metaspace GCFull GC最核心的变化点面试高频JDK 8 开始永久代被彻底移除元空间Metaspace取代了它元空间使用本地内存Native Memory不再受 -XX:MaxPermSize 限制元空间默认情况下可以动态增长受系统可用虚拟内存限制2. 方法区到底存放什么元数据内容无论永久代还是元空间方法区主要存储以下内容类信息Class Metadata类名、父类名、接口列表字段Field信息名称、类型、修饰符、属性值static final 常量方法Method信息名称、描述符、字节码、异常表、局部变量表、操作数栈大小等运行时常量池Runtime Constant PoolClass 文件中常量池表的运行时表示字面量Literal文本字符串、声明为 final 的基本类型常量符号引用Symbolic Reference类和接口的全限定名、字段名和描述符、方法名和描述符静态变量类变量static 修饰的变量JDK 7 之前在永久代JDK 7 开始移到普通堆对 JIT 编译器产生的代码缓存部分版本注意静态变量本身在 JDK 7 之后已经不在方法区了而是放在堆的普通对象实例中但 static final 常量仍可能留在运行时常量池。3. 运行时常量池Runtime Constant Pool详解运行时常量池是方法区非常重要的一部分也是最容易和“字符串常量池”混淆的区域。包含内容字面量如hello、100、true符号引用类、方法、字段的符号引用在类加载的解析阶段会被解析为直接引用字符串常量池的变迁常考JDK 版本字符串常量池位置是否在方法区说明JDK 6 及之前永久代是字符串常量池在方法区JDK 7堆普通堆内存否永久代中移出字符串常量池JDK 8堆元空间不包含字符串池否字符串常量池在堆中元空间只存类元数据经典面试题Strings1hello;Strings2newString(hello).intern();System.out.println(s1s2);// true 或 false 为什么JDK 7trueintern() 会把字符串放入字符串常量池并返回引用4. 元空间Metaspace vs 永久代PermGen对比项永久代PermGen元空间Metaspace内存位置堆内存本地内存Native Memory大小固定吗是-XX:MaxPermSize否动态增长默认无上限容易 OOM 的场景类加载过多、大量动态代理、大量反射类加载非常多时也会耗尽系统虚拟内存GC 回收Full GC 时回收Metaspace Full GC调优参数-XX:PermSize -XX:MaxPermSize-XX:MetaspaceSize -XX:MaxMetaspaceSize推荐调优参数生产环境常见-XX:MetaspaceSize256m# 初始触发 Full GC 的阈值不是分配大小-XX:MaxMetaspaceSize512m# 最大元空间大小建议设置上限防止耗尽物理内存5. 方法区 / 元空间 OOM 的常见场景真实案例大量动态代理 / CGLIB / JDK ProxySpring AOP、MyBatis 动态 mapper大量反射如 JSON 框架大量使用反射大量类加载OSGi、插件系统、热部署系统大量 JSP 编译Tomcat 动态编译 JSPGroovy / Scala 等动态语言特性解决思路增大 Metaspace 大小-XX:MaxMetaspaceSize优化代码减少不必要的类加载使用类加载隔离如 tomcat 的 WebappClassLoader6. 总结一句话记住方法区方法区是存放已被加载的类元数据类结构、方法字节码、运行时常量池等的地方。JDK 6及之前叫永久代在堆里固定大小JDK 8及之后叫元空间在本地内存动态扩展字符串常量池和 static 变量在 JDK7 已经移到普通堆如果你现在想继续深入可以告诉我你想重点看哪个方向运行时常量池的详细解析过程intern() 方法底层实现类加载机制与方法区的关系元空间 OOM 真实案例分析方法区与堆、栈的对比图随时说