方法区是JVM规范定义的逻辑区域,永久代(JDK 1.6及之前)和元空间(JDK 1.8+)是HotSpot对其的不同实现;JDK 1.7为过渡期,字符串常量池迁出永久代至堆中。

方法区是 JVM 规范定义的逻辑内存区域,用于存储类信息、常量池、静态变量、JIT 编译代码等;而元空间和永久代,只是 HotSpot 虚拟机在不同 JDK 版本中对它的具体实现方式。理解演进的关键,在于区分“规范”和“实现”——方法区始终存在,变的只是底层怎么存、谁来管、怎么回收。
JDK 1.6 及之前:永久代(PermGen)完全承担方法区职责
永久代是堆内存的一部分,物理上与新生代、老年代并列。它统一存放:
- 类元数据(Klass 结构)、运行时常量池
- 字符串常量池(StringTable,当时还在 PermGen 中)
- 静态变量、符号引用、JIT 编译后的本地代码
配置参数为:-XX:PermSize=64M(初始大小)、-XX:MaxPermSize=256M(最大上限)。问题明显:大小固定,Full GC 才回收,字符串常量多或动态生成类(如反射、Groovy、CGLIB)极易触发 java.lang.OutOfMemoryError: PermGen space。
JDK 1.7:永久代过渡期,字符串常量池迁出
HotSpot 开始拆分压力,将字符串常量池(StringTable)和部分符号引用移到堆内存中。永久代仍保留类元数据、常量池主体、静态变量和 JIT 代码,但不再存字符串字面量。
立即学习“Java免费学习笔记(深入)”;
在 Java 中初始化和管理阿里云 SDK客户端。包括单例模式、线程安全、endpoint 与 region 配置、VPC 终端节点、同步与异步等。
此举让字符串能随堆对象一起被 Minor GC 或 G1 的年轻代回收,显著缓解内存压力。配置参数保持不变,但实际占用下降,OOM 风险降低。例如执行 "hello".intern() 生成的字符串实例,此时已位于堆中而非 PermGen。
JDK 1.8 及之后:元空间(Metaspace)替代永久代
永久代被彻底移除,元空间成为方法区的新实现。关键变化是:元空间使用**本地内存(Native Memory)**,不再属于 JVM 堆,由操作系统直接管理。
- 存储内容聚焦类元数据(Klass、Method、ConstantPool 等),不存字符串、静态变量(它们归堆管)
- 默认无上限(
-XX:MaxMetaspaceSize不设则耗尽系统内存),更灵活 - 有独立的元空间 GC,类卸载后可及时释放内存,回收更精细
常用配置:-XX:MetaspaceSize=64M(触发首次元空间 GC 的阈值,非初始大小)、-XX:MaxMetaspaceSize=256M(硬性上限)、-XX:MinMetaspaceFreeRatio 和 -XX:MaxMetaspaceFreeRatio 控制自动扩容收缩行为。
配置与调优要点
从 JDK 8 开始,不要再用 -XX:PermSize 类参数,否则 JVM 启动会报错。线上服务建议显式设置 -XX:MaxMetaspaceSize,防止元空间无限增长挤占系统资源。若应用大量使用字节码生成(如 Spring AOP、MyBatis Mapper 动态代理),需适当调高该值,并关注 GC 日志中 Metadata GC Threshold 和 Metaspace 区域的使用趋势。监控时可通过 jstat -gc <pid> 查看 MU(Metaspace used)、MC(Metaspace capacity)指标。

















