string.intern()可能导致内存泄漏:它将字符串强引用存入常量池,使对象无法被gc回收;jdk7+常量池在堆中,大量唯一字符串intern会膨胀哈希表、触发oom或g1回收bug,且高并发下锁竞争加剧性能损耗。

String.intern() 本身不直接“泄漏”内存,但它会让字符串长期驻留在字符串常量池中,而常量池里的对象只要被持有,就不会被 GC 回收——哪怕原字符串早已脱离作用域。这种“本该回收却无法回收”的状态,就是典型的内存泄漏。
常量池变成长期持有者
调用 intern() 后,JVM 会把字符串(或其引用)放入字符串常量池。从 JDK 7 开始,常量池在堆内存中;它和普通对象一样受 GC 管理,但有个关键限制:只要池中还存着这个字符串的引用,GC 就不会清理它对应的实际字符串对象。
- 比如反序列化大量用户 ID:
Map<long string></long>中的 key 是动态生成的 userId 字符串,Jackson 默认会对字段名 intern —— 若 userId 每次都不同(如"user_123456789"),每个都会进池,且永不退出 - 这些字符串不会因为业务逻辑结束、变量出作用域就消失;它们被常量池强引用着,持续占用堆空间
池大小失控引发 OOM
字符串常量池底层是哈希表,默认容量有限(JDK 8 是 60013,可通过 -XX:StringTableSize 调整)。当大量唯一字符串不断 intern,池会扩容、锁竞争加剧,同时占用更多堆内存。
在 Java 中初始化和管理阿里云 SDK客户端。包括单例模式、线程安全、endpoint 与 region 配置、VPC 终端节点、同步与异步等。
- 高频调用 intern() 处理随机内容(如日志片段、HTTP header 值、UUID)时,池可能迅速膨胀
- 一旦接近或超过 JVM 堆上限,就会抛
OutOfMemoryError: Java heap space,而非方法区错误 - 更隐蔽的是:某些 JDK 版本(如 JDK 8u192 之前)存在 G1 GC 对 interned string 回收不及时的 bug(JDK-8180048),加剧泄漏
行为不可控埋下逻辑隐患
常量池不是无限增长的。超出容量或触发内部限制时,JVM 可能跳过入池操作,直接返回原字符串引用——这意味着 str.intern() == str 有时为 true,有时为 false。
- 代码若依赖
==判断字符串相等(例如做轻量级缓存或状态标识),结果会随字符串是否成功入池而波动 - 这种非确定性很难在测试中复现,上线后表现为偶发逻辑错误,排查成本极高
性能损耗反向放大问题
intern() 不是零成本操作:每次都要查哈希表、加锁、可能扩容。在高并发场景下,它反而成为瓶颈。
- 大量线程争抢字符串表锁,导致吞吐下降、响应延迟升高
- 为“省内存”引入的 intern,实际因锁竞争和 GC 压力,整体内存与 CPU 开销双双上升
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南










