可以,但有条件。JDK7及以后字符串常量池位于堆内存中,池中存储的是对堆中字符串对象的引用,只要该字符串对象无任何强引用,就和普通堆对象一样可被GC回收。

Java 中字符串常量池的清理不是主动“清空”,而是由垃圾回收器(GC)按需回收——前提是池中某个字符串对象已**不再被任何强引用指向**。
常量池里的字符串能被 GC 回收吗?
可以,但有条件。JDK7 及以后,字符串常量池位于堆内存中,池中存储的是对字符串对象的引用(不是对象本身),而这些字符串对象本身也存于堆中。只要该字符串对象没有其他强引用(比如局部变量、静态字段、集合容器等),它就和普通堆对象一样,可被 GC 标记并回收。
- 字面量创建的字符串(如
String s = "abc")会驻留池中,只要类加载器还活着、且该字符串被静态常量或运行时代码持续引用,就不会被回收 -
new String("abc").intern()生成的池中引用,若后续所有指向它的变量都置为null,且无其他间接引用,Full GC 时可能将其回收 - Minor GC 一般不扫描字符串常量池;只有 Full GC 或某些 G1/ZGC 的并发标记阶段才会检查并清理无引用的池项
GC 清理的实际触发场景
字符串常量池本身不维护引用计数,完全依赖 JVM 的可达性分析。常见可回收情形包括:
- 动态生成大量唯一字符串后调用
intern(),随后丢弃全部引用,且长时间未再使用——多次 Full GC 后可能逐步释放 - Web 应用中,临时加载的类(如热部署场景)所带的字符串字面量,在类卸载后,若其字符串未被其他类共享,也可能被回收
- 使用反射或动态代理生成的类名、方法名等字符串,一旦关联的 Class 对象被卸载,对应字符串若无其他引用,也会成为回收目标
如何观察和调优清理行为
可通过 JVM 参数辅助诊断:
立即学习“Java免费学习笔记(深入)”;
-
-XX:+PrintStringTableStatistics:每次 GC 后打印池中桶数量、条目数、平均链长等,帮助判断是否堆积 -
-XX:StringTableSize=N:设置哈希表桶数量(建议质数,如 60013),减少哈希冲突,提升查找与清理效率 -
jcmd <pid> VM.native_memory summary或jstat -gc <pid>结合观察老年代变化,间接推测池中字符串回收情况
需要注意的误区
很多人误以为常量池“永不清理”或“自动定时清空”,其实:
- 池中字符串不会因“过期”或“闲置时间长”被回收——只看是否可达
-
intern()不是万能优化手段:高频调用可能造成池膨胀,反而增加 GC 压力 - 字符串内容相同 ≠ 引用相同:
new String("x").intern() == "x"成立,但前提是该字符串尚未被回收且仍可达


















