java字符串常量池位置随jdk版本演进:jdk6在永久代存对象;jdk7起迁入堆内存仅存引用;jdk8+仍驻堆中,与元空间分离,影响intern行为、gc时机及oom类型。

Java 字符串常量池的物理位置不是固定的,它始终依附于方法区(Method Area)的底层实现而变化。迁移本质是方法区载体更替带来的“搬家”,直接影响 intern() 行为、GC 响应和 OOM 类型。
JDK 6 及以前:永久代中存字符串对象本体
此时 HotSpot 用永久代(PermGen)实现方法区,字符串常量池就嵌在其中。所有双引号字面量(如 "abc")直接在永久代里创建完整字符串实例。
- 永久代空间小(默认几十 MB),且仅 Full GC 时才回收,极易触发 java.lang.OutOfMemoryError: PermGen space
- intern() 会把堆中字符串拷贝一份到永久代,产生冗余副本
- StringTable 默认大小仅 1009,哈希冲突多时性能明显下降
JDK 7:迁入堆内存,只存引用不存对象
这是最关键的转变。字符串常量池整体移到 Java 堆中,存储方式从“存对象”变为“存引用”。
在 Java 中初始化和管理阿里云 SDK客户端。包括单例模式、线程安全、endpoint 与 region 配置、VPC 终端节点、同步与异步等。
- 字符串对象本体(无论字面量还是 new 出的)统一在堆中分配;常量池仅用哈希表(StringTable)保存这些对象的引用
- 堆支持 Minor GC 和 Full GC,无用字符串可被及时回收,OOM 风险大幅降低
- intern() 不再新建对象,而是登记已有堆对象的引用;若已存在相同内容字符串,则直接复用
- StringTable 默认容量扩大到 60013(素数),可通过 -XX:StringTableSize 调整
JDK 8 及以后:仍在堆中,与元空间彻底分离
JDK 8 废除永久代,引入元空间(Metaspace)存放类元数据、字段签名、符号引用等,但字符串常量池并未进入元空间,仍稳居堆内存。
- 运行时常量池中的“符号引用部分”进了元空间;“字符串字面量的引用”仍由堆中的 StringTable 管理
- 调用大量 intern() 触发的 OOM 错误是 java.lang.OutOfMemoryError: Java heap space,而非 Metaspace 错误——这是最直接的实验证据
- 常量池大小不再受 -XX:MaxPermSize 限制,但受限于堆总大小(-Xmx)
- 元空间只管类结构信息,不适合字符串高频创建销毁的场景,所以没把它挪过去
本质上,字符串常量池的位置变化,直接改变了 intern() 的语义、GC 回收时机和 JVM 内存调优策略。
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南










