方法区是jvm规范定义的逻辑区域,非物理分区;永久代(jdk7及以前)和元空间(jdk8起)是hotspot对其的具体实现,前者位于堆内、大小固定、回收困难,后者使用本地内存、动态扩容、卸载更及时。

方法区是 JVM 规范定义的逻辑区域,不是物理内存分区;永久代和元空间,都是 HotSpot 虚拟机对它的具体实现——前者用于 JDK 7 及以前,后者从 JDK 8 开始取代前者。
方法区:规范层面的“类元数据仓库”
它属于 JVM 规范强制要求的线程共享区域,必须存储以下内容:
- 已加载类的结构信息(类名、父类、接口、访问修饰符)
- 字段与方法的描述(名称、类型、签名、字节码、异常表)
- 运行时常量池、静态变量、符号引用
- 即时编译器生成的本地代码缓存
注意:方法区在逻辑上属于堆的一部分,但为区分常被称作“非堆”。它不存放普通 Java 对象(对象在堆中),只存“类本身的信息”。任何 JVM 实现都得提供一块地方来满足这些需求,但怎么实现,规范不管。
永久代:HotSpot 在堆内划出的“老式方法区”
JDK 1.6–1.7 中,HotSpot 把方法区实现在 Java 堆内部的一个独立子区域,叫永久代(PermGen):
当用户要求为 Java 代码添加注释、修改注释、审查注释、整理注释格式,或要求按照代码注释规范处理 Java 文件时,使用本技能。本技能用于统一生成和维护 Java 类注释模板、按 Git 对比 release 判断版本号、补充每行代码上方中文块注释、调整注释空行规则,并保持 Java 文件 UTF-8 无 BOM 编码。典型触发场景包括:补充类注释、更新 @version、检查 @author 来源、整理行尾注释、把注释放到代码上一行、检查注释是否符合规范、构建前检查 Java 注释风格。
- 位置在堆内存中,受 -Xmx 等堆参数间接影响
- 大小需显式配置:-XX:PermSize 和 -XX:MaxPermSize
- 回收条件苛刻:只有当类实例、类加载器、Class 对象全部不可达时才可能卸载类
- 典型问题:JSP 编译、CGLib 动态代理、OSGi 插件场景下容易触发 java.lang.OutOfMemoryError: PermGen space
本质是把“长期稳定”的元数据,和“频繁变动”的对象堆混在一起管理,GC 效率低、调优难、扩展性差。
元空间:改用本地内存的“新式方法区”
JDK 8 起,HotSpot 彻底移除永久代,改用元空间(Metaspace)实现方法区:
- 位置在本地内存(Native Memory),不受 JVM 堆大小限制
- 默认无上限(受限于系统可用内存和 -XX:MaxMetaspaceSize 设置)
- 类卸载更及时:只要类加载器被回收,其加载的类元数据就可被清理
- 仍会 OOM,但错误提示变为 java.lang.OutOfMemoryError: Metaspace,原因多为类加载器泄漏或动态类爆炸增长
这相当于把“大脑的长时记忆区”从拥挤的主城区(堆)搬进独立规划的新城区(本地内存),GC 不再需要暂停整个堆,稳定性与伸缩性明显提升。
关键区别一句话总结
方法区是接口,永久代和元空间是两个不同版本的实现类;前者在堆里、固定大小、回收难;后者在堆外、弹性扩容、回收更合理。
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南










