JVM--方法区(Method Area)
JVM–方法区(Method Area)
背景
-
JVM–方法区(Method Area)
-
博主以黑马JVM进行学习
定义
- 方法区是 JVM 中线程共享的内存区域,用于存储已被虚拟机加载的类元数据(类的结构信息)、常量、静态变量、即时编译器编译后的代码缓存等;
- 补充:方法区是 JVM 规范中的逻辑概念,不同 JVM 实现有不同的物理载体(1.6 用永久代,1.8 用元空间)。
组成
-
JVM内存结构1.6
- 方法区(概念):PermGen永久代(实现)包括:常量池(StringTable)、Class、ClassLoader
-
JVM内存结构1.8
- 方法区(概念):Metaspace元空间(实现)(包括:常量池、Class、ClassLoader)(由本地内存管理),堆(包含StringTable)
-
比较
JVM 版本 方法区的实现方式 核心组成 关键差异 JDK 1.6 永久代(PermGen,属于堆内存的一部分) 1. 类元数据(Class 结构、字段 / 方法信息)2. 运行时常量池(包含 StringTable)3. 静态变量4. ClassLoader 相关信息 永久代受 JVM 堆内存限制,可通过 -XX:MaxPermSize限制大小JDK 1.8 元空间(Metaspace,属于本地内存 / 直接内存) 1. 类元数据、静态变量、ClassLoader 信息(存储在元空间)2. 运行时常量池(仍属于方法区逻辑范畴)3. StringTable(移至堆内存) 元空间默认使用本地内存(不受 JVM 堆限制),可通过 -XX:MaxMetaspaceSize限制
方法区的内存溢出
-
1.8以前会导致永久代内存溢出(OutOfMemoryError: PermGen space)
- -XX:MaxPermSize=内存大小
-
1.8之后会导致元空间内存溢出(OutOfMemoryError: Metaspace)
-
元空间大小根据物理内存大小
-
-MaxMetaspaceSize=内存大小
-
-
比较
版本 溢出错误 核心参数 参数说明 JDK 1.6- OutOfMemoryError: PermGen space-XX:PermSize(初始永久代大小)-XX:MaxPermSize(最大永久代大小)默认值较小(比如 64M),超出则溢出 JDK 1.8+ OutOfMemoryError: Metaspace-XX:MetaspaceSize(元空间初始阈值,触发 GC 的阈值)-XX:MaxMetaspaceSize(元空间最大大小)默认无上限(耗尽本地内存才溢出),建议显式设置上限 -
场景:
核心原因:动态生成大量类,导致类元数据占满方法区
- spring:通过 CGLIB/JDK 动态代理生成大量代理类;
- mybatis:Mapper 接口动态生成实现类;
- 其他:反射、动态字节码生成(ASM/ClassWriter)、热部署频繁加载类;
运行时常量池(Constant pool)
-
常量池,就是一张表,虚拟机指令根据这张常量表找到要执行的类名、方法名、参数类型、字面量等信息
-
运行时常量池,常量池是*.class文件中的,当该类被加载,它的常量池信息就会放入运行时常量池,并把里面的符号地址变为真实地址
-
.class文件的核心组成: -
二进制字节码 = 类基本信息 + 常量池 + 类方法定义(含虚拟机指令) + 字段定义
-
虚拟机指令通过常量池的索引查找数据:比如指令
ldc #1表示加载常量池第 1 项的字面量; -
JDK中的javap -v反编译后显示详细信息
总结
- 方法区是 JVM 线程共享的逻辑区域,JDK 1.6 用永久代(堆内)实现,JDK 1.8 改用元空间(本地内存)实现,核心变化是 StringTable 移至堆、元空间不受堆内存限制;
- 方法区溢出在 1.6 表现为
PermGen space,1.8 表现为Metaspace,核心场景是动态生成大量类(Spring/MyBatis 代理),可通过-XX:MaxPermSize/-XX:MaxMetaspaceSize限制大小; - 运行时常量池是类加载后常量池的运行时形态,存储字面量和符号引用(加载后转为直接引用),具备动态性,是虚拟机指令执行的核心数据来源。
补充
- 元空间不是堆内存,而是本地内存,默认无上限,需手动设置
-XX:MaxMetaspaceSize防止耗尽系统内存; - StringTable(字符串常量池)在 1.8 移至堆,因此字符串相关的内存溢出是
Java heap space,而非元空间溢出; - 运行时常量池≠字符串常量池:前者包含后者(1.6),1.8 后字符串常量池独立在堆中,运行时常量池仍在元空间(逻辑上属于方法区)。