java字符串常量池通过复用相同字符串对象减少内存占用,字面量自动入池,new string()产生冗余堆对象;高重复运行期字符串可谨慎intern();jdk9+紧凑字符串自动节省空间;intern()非通用缓存,滥用损害性能。

Java 中字符串常量池本身不主动“压缩”数据,而是通过安全复用相同内容的字符串对象来减少内存占用、提升引用比较效率。优化的关键在于理解其行为机制,并在编码中做出合理选择。
字面量自动入池,避免堆上冗余对象
用双引号定义的字符串(如 "GET"、"200"、"active")在类加载时就进入常量池,后续相同字面量直接复用同一对象。
- ✅ 推荐:
String method = "POST";→ 栈变量指向池中唯一实例,无额外堆分配 - ❌ 避免:
String method = new String("POST");→ 每次都在堆新建一个 String 对象,即使 value 数组复用池中底层数组,对象头和引用本身仍是冗余开销 - ⚠️ 注意:
"POST".intern()对已存在的字面量无效,纯属多余调用,还多一次哈希查找
运行期高重复字符串可谨慎调用 intern()
从数据库、配置中心或网络读取的字符串,若满足以下条件,适合显式调用 intern():
- 内容重复率高(如状态码 "SUCCESS"、币种 "USD"、协议版本 "v2")
- 生命周期长、作为 key 频繁使用(如缓存 key、Map 的键、枚举标识)
- 示例:
String status = resultSet.getString("status").intern();
效果:10 万条记录中若有 9 万个 "SUCCESS",经 intern() 后仅保留 1 个对象,而非 9 万个独立堆实例。
JDK 9+ 紧凑字符串自动节省空间
无需改代码,JVM 自动启用:当字符串所有字符 Unicode 值 ≤ 127(即 Latin-1 字符,如英文、数字、常见符号),内部改用 byte[] 存储,每个字符占 1 字节,相比旧版 char[](2 字节)节省约 50% 内存。
- 完全透明:
length()、charAt()、substring()行为不变 - 验证方式:可用 JOL(Java Object Layout)工具查看实际内存布局
慎用 intern(),它不是通用缓存方案
intern() 是全局同步操作,底层依赖哈希表查表 + 加锁,滥用会拖慢性能甚至引发内存问题:
- ❌ 禁止对唯一值调用:UUID、时间戳、随机 token —— 几乎不重复,
intern()后白占空间且难回收 - ❌ 避免在循环内无条件调用:每次触发哈希查找与锁竞争,成为性能瓶颈
- ? 提示:
intern()返回的是常量池中的引用,原堆对象仍存在;==可验证是否复用成功(如new String("x").intern() == "x"为 true)
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











