方法区是JVM规范定义的逻辑区域,非堆内存的一部分,用于存储类元数据;JDK 8起由元空间实现,使用本地内存,存放类型信息、常量池、静态变量等,String常量池已移至堆中。

方法区是JVM规范定义的逻辑区域,不是堆内存的一部分
方法区(Method Area)是Java虚拟机规范中规定的一块用于存储类元数据的内存区域,它和堆、栈、本地方法栈、程序计数器并列。注意:方法区本身不对应某一块具体物理内存——在HotSpot JVM 8及以前,它由永久代(PermGen)实现;JDK 8开始,永久代被元空间(Metaspace)取代,元空间使用本地内存(native memory),不再受-XX:MaxPermSize限制,而是由-XX:MaxMetaspaceSize控制。
方法区里到底存哪些类元数据
方法区主要存放已被虚拟机加载的类型信息,包括:
-
类的全限定名、父类的全限定名、实现的接口列表 -
字段信息(名称、类型、修饰符)、方法信息(签名、字节码、异常表、栈帧大小等) -
常量池(运行时常量池,Runtime Constant Pool),含字面量、符号引用(如类/字段/方法名) -
静态变量(static fields)—— 注意:静态变量本身存放在方法区,但其引用的对象实例仍存在堆中 -
即时编译器编译后的代码缓存(如HotSpot的C1/C2编译结果)
常见误判:String常量池不在方法区
很多人以为"abc"这类字符串字面量存在方法区,其实不是:
- JDK 7+:字符串常量池已从方法区(永久代)移到
堆内存中,位于堆的老年代(或G1中的Humongous Region) - 只有
Class对象本身(即java.lang.Class实例)在堆中,但它指向的方法区中的类元数据才是真正的类型定义 - 可通过
String.intern()把堆中字符串引用注册到字符串常量池,但注册行为不改变原字符串所在位置
元空间OOM和排查关键点
使用JDK 8+后,java.lang.OutOfMemoryError: Metaspace比旧版的PermGen space更常见,但原因不同:
立即学习“Java免费学习笔记(深入)”;
- 默认情况下
-XX:MaxMetaspaceSize无上限(仅受系统内存限制),容易因大量动态类生成(如Spring Boot热部署、Groovy脚本、CGLIB代理、OSGi)撑爆本地内存 -
ClassLoader泄漏是主因:每个类加载器都维护一份独立的元空间,若类加载器无法被GC回收,其加载的所有类元数据也无法释放 - 排查建议:
jstat -gcmetacapacity
查看元空间容量与使用量;jmap -clstats
统计各ClassLoader加载的类数量;用jcmd确认是否真为元空间耗尽而非其他本地内存问题VM.native_memory summary
ClassLoader可能拖住几十MB元数据,而这种泄漏在线上往往只在数天后才暴露。










