运行时常量池是类加载时从Class文件常量池动态创建的内存区域,属于方法区或元空间,存储解析后的符号引用和运行期新增条目;字符串常量池是独立堆内存区域,二者物理分离、协同工作。

Java中的运行时常量池(Runtime Constant Pool)是每个类或接口在加载到JVM时,从其Class文件的常量池(Constant Pool)中映射出来的一块内存区域,属于方法区(JDK 7及以前)或元空间(JDK 8+)的一部分。它不是编译期静态存在的“表”,而是在类加载阶段动态创建、并在运行期间可扩展的符号引用集合,用于支撑反射、动态绑定、字符串拼接优化等关键机制。
运行时常量池和Class文件常量池的区别
Class文件常量池是编译后写入.class字节码的静态结构,包含字面量(如字符串字面量、数字常量)和符号引用(如类名、字段名、方法名)。而运行时常量池是JVM在类加载时,将Class常量池内容载入内存后的“活”的版本——它会解析部分符号引用(如类、方法),缓存实际对象(如String实例、Class对象),并支持运行期新增内容(如通过String.intern()加入字符串、Lambda生成的引导方法句柄等)。
字符串常量池是运行时常量池的一部分吗?
不是。这是常见误解。字符串常量池(String Table)是独立于运行时常量池的另一块内存区域,位于堆中(JDK 7起)或本地位于元空间但引用指向堆(JDK 8+)。它专门缓存通过字面量声明或调用intern()方法加入的字符串对象。而运行时常量池里只保存字符串字面量的引用索引(比如#12 → "hello"),真正对象存储在字符串常量池中。两者协同工作,但物理分离、管理独立。
哪些操作会影响运行时常量池的内容?
以下行为会在运行期向运行时常量池添加或解析条目:
立即学习“Java免费学习笔记(深入)”;
- 首次访问某个类的静态字段或调用静态方法,触发类初始化,相关符号引用被解析为直接引用
- 执行String.intern():若字符串已存在则返回引用;否则将其加入字符串常量池,并在运行时常量池中建立对应索引
- 使用invokedynamic指令(如Lambda表达式、方法引用):首次执行时会注册引导方法,相关信息存入运行时常量池
- 反射调用Class.forName()或Method.invoke():可能触发符号引用解析和缓存
运行时常量池溢出会发生什么?
当大量动态生成类(如CGLIB代理、JSON序列化框架反复生成类)、或频繁调用intern()且字符串不可回收时,运行时常量池可能占满方法区/元空间。此时抛出java.lang.OutOfMemoryError: Metaspace(JDK 8+)或java.lang.OutOfMemoryError: PermGen space(JDK 7及以前)。可通过-XX:MaxMetaspaceSize或-XX:MaxPermSize调优,但更应排查动态类生成逻辑是否合理。










