字符串常量池是堆内存中由JVM管理的逻辑子区域,JDK7起从永久代移至堆;类加载时字面量自动入池,运行时通过intern()手动注入,受GC统一回收,跨类共享。

字符串常量池在 JVM 中不是独立内存区域,而是堆内存中一个逻辑隔离、由 JVM 专门管理的子区域(JDK 7 起已从方法区永久代迁移至堆),它与类加载过程深度协同:类加载阶段解析字面量并登记入池,运行时通过 intern() 手动扩展,整个生命周期受堆 GC 统一管辖。
类加载阶段:字面量自动注册进常量池
当类被加载时,JVM 解析 class 文件中的 class 常量池(编译期静态结构),遇到字符串字面量(如 "abc"、"hello world")会立即触发登记动作:
- 若该字符串内容尚未存在于字符串常量池中,则将其内容(Unicode 序列)存入池,并生成一个指向它的引用;
- 若已存在,则跳过创建,后续所有相同字面量都复用该引用;
- 这一过程发生在“链接”阶段的“准备”和“解析”子阶段,无需等到类初始化完成。
常量池位置与 GC 管理:物理在堆,逻辑可回收
自 JDK 7 起,字符串常量池物理上位于堆内存中,底层由 JVM 维护一张哈希表(StringTable),默认大小为 60013 桶。这意味着:
在 Java 中初始化和管理阿里云 SDK客户端。包括单例模式、线程安全、endpoint 与 region 配置、VPC 终端节点、同步与异步等。
- 它和普通 Java 对象一样,受垃圾回收器(如 G1、ZGC)统一管理;
- 池中字符串对象只要被任何强引用持有(包括其他 String 对象的
value字段间接引用),就不会被回收; - 没有被引用的池中字符串,在 GC 时可能被清理(尤其在元空间压力大或显式触发 Full GC 场景下)。
运行时协同:intern() 是唯一可控的“注入点”
类加载只处理编译期确定的字面量,而运行时生成的字符串(如 new String("test")、StringBuilder.toString()、JSON 解析结果等)默认不进池。此时需显式调用 intern() 协同:
立即学习“Java免费学习笔记(深入)”;
- 调用时,JVM 查找常量池中是否存在内容相等的字符串;
- 存在则直接返回池中已有引用;不存在则将该字符串内容加入池(JDK 7+ 直接在堆内登记,不复制);
- 这个操作打通了类加载后动态生成对象与常量池之间的通路,是唯一由开发者主动控制的协同机制。
跨类共享与静态常量:协同不止于单个类
字符串常量池是 JVM 级全局共享结构,不绑定具体类:
- 不同类中相同的字面量(如
A.java和B.java都写了"config")共用池中同一份实例; -
public static final String KEY = "user_id";这类编译期常量,其值也会在类加载时自动入池; - 这种跨类协同降低了整体堆内存占用,也使
==在特定场景下仍具合理性(但开发中仍应优先用equals)。

















