运行时常量池 和 字符串常量池 区别
运行时常量池与字符串常量池的区别
运行时常量池(Runtime Constant Pool)和字符串常量池(String Constant Pool)都是JVM中用于存储常量的区域,但它们有以下关键区别:
1. 存储内容不同
常量池类型 | 存储内容 |
---|---|
运行时常量池 | 类文件中常量池表(Constant Pool Table)的所有内容: • 类/方法/字段的符号引用 • 字面量(Literal) • 编译期数字常量 • 方法类型/句柄等 |
字符串常量池 | 只存储字符串对象的引用(实际字符串对象在堆中) |
2. 数据结构实现不同
java
// 字符串常量池实际是HashTable结构 String s1 = "hello"; // 会先检查字符串常量池 String s2 = new String("hello"); // 会在堆创建新对象// 运行时常量池是类文件结构的运行时表示 class Demo {final int MAX = 100; // 常量会进入运行时常量池void method() {Class<?> clazz = Demo.class; // 类符号引用在运行时常量池} }
3. 所在内存区域不同
常量池类型 | Java 7之前位置 | Java 7及之后位置 |
---|---|---|
运行时常量池 | 方法区(PermGen) | 元空间(Metaspace) |
字符串常量池 | 方法区(PermGen) | 堆(Heap) |
4. 交互方式不同
java
// 字符串常量池的特殊操作 String.intern(); // 可以主动将字符串放入常量池// 运行时常量池只能通过类加载过程填充 // 没有直接操作的API
5. 生命周期不同
常量池类型 | 生命周期 |
---|---|
运行时常量池 | 随Class对象存在,类卸载时才会清除 |
字符串常量池 | 存在于堆中,随GC回收(但被引用的字符串不会被回收) |
实际案例分析
java
public class ConstantPoolDemo {public static void main(String[] args) {// 字符串常量池行为String s1 = "java";String s2 = new String("java");System.out.println(s1 == s2); // false// 运行时常量池行为Class<ConstantPoolDemo> clazz = ConstantPoolDemo.class;System.out.println(clazz.getName()); // 类名引用来自运行时常量池} }
总结对比表
特性 | 运行时常量池 | 字符串常量池 |
---|---|---|
存储内容 | 类文件常量池表所有内容 | 仅字符串引用 |
实现结构 | 类文件结构的运行时表示 | 哈希表 |
Java 7+位置 | 元空间 | 堆 |
操作方式 | 类加载时自动填充 | 可通过intern()方法操作 |
垃圾回收 | 随类卸载清除 | 受GC管理 |
主要用途 | 支持类加载、解析、动态链接等JVM操作 | 优化字符串存储,减少重复创建 |
理解这两个常量池的区别对于掌握以下内容很重要:
类加载机制
字符串内存优化
内存泄漏分析
性能调优