在 Java 中,String 本身不会“主动”造成内存泄漏,但由于 Java 的设计和历史实现(尤其是 JDK 6 及以前),如果使用不当,String 很容易成为内存泄漏的“帮凶”甚至直接原因。
下面从原理到常见场景系统说明。
核心原因有三点:
char[](或 byte[])substring() 导致的内存泄漏(最经典)String big = readBigFile(); // 假设 10MB
String small = big.substring(0, 10);
// JDK 6 内部
String {
char value[];
int offset;
int count;
}
small 和 big 共享同一个 char[]✅ 后果:
只要 small 还活着,big 的整个数组都无法释放
small = new String(small);
或
small = small.intern();
✅ JDK 7+ 已修复
substring() 会创建新的 char[]String.intern() 使用不当(常量池泄漏)String s = new String("abc").intern();
for (...) {
String key = readFromUser(); // 用户输入
key.intern(); // ❌ 无限增长
}
✅ 后果:
⚠️ 不要用 intern 存动态、不可控字符串
public static Map<String, String> cache = new HashMap<>();
cache.put(bigString, bigString);
只要 cache 不清理:
✅ 解决方案:
WeakHashMapcatch (Exception e) {
errorLog.put(e.getMessage()); // 大字符串
}
new String(bytes, "UTF-8");
| 版本 | 关键问题 |
|---|---|
| JDK 6 | substring 共享数组、intern 在 PermGen |
| JDK 7 | substring 修复、intern 移到堆 |
| JDK 8+ | 常量池在 Metaspace |
| JDK 9+ | String 改用 byte[] + coder |
✅ 建议做法:
intern()WeakReferenceString 本身不会泄漏,但“长期引用 + 共享数组 + 常量池”会让它成为内存杀手。
如果你有具体场景(如缓存、Netty、日志、JVM 版本),我可以帮你精准分析。
免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。