JVM 常量池溢出排查:在 JDK 6 中由于 String.intern 导致的永久代溢出修复方案
JDK6中String.intern()会将字符串复制到永久代且不可回收,易引发java.lang.OutOfMemoryError:PermGenspace;应禁用滥用,改用ConcurrentHashMap等可控缓存替代。临时应急可调整-XX:MaxPermSize参数扩容,但此方法在后续JDK版本已废弃。修复后需通过监控工具观察永久代使用趋势,确保问题
JVM 常量池溢出排查:在 JDK 6 中由于 String.intern 导致的永久代溢出修复方案

在 JDK 6 的时代,String.intern() 方法堪称是永久代(PermGen)内存溢出的“头号嫌疑人”。原因很直接:当时的字符串常量池就坐落在永久代里。每一次对 intern() 的调用,都意味着会将堆中的字符串对象完整复制一份到永久代。问题在于,永久代那点“家底”通常很薄(默认只有几MB),而且这块区域不受常规垃圾回收(GC)的管辖,一旦被大量复制的字符串填满,ja va.lang.OutOfMemoryError: PermGen space 的报错也就不请自来了。
JDK6中String.intern()会将字符串复制到永久代且不可回收,易引发ja va.lang.OutOfMemoryError: PermGen space;应禁用滥用,改用ConcurrentHashMap等可控缓存替代。
确认是否为常量池导致的 PermGen 溢出
诊断的第一步,是看准异常信号。如果抛出的 OOM 错误明确写着:
ja va.lang.OutOfMemoryError: PermGen space
并且,在异常堆栈信息里,发现了 String.intern(Native Method) 或者类似的调用踪迹,那么基本就可以锁定元凶了。这是最直观、最关键的判断依据。
临时缓解:扩大永久代空间(仅限应急)
当线上问题火烧眉毛时,可以通过调整 JVM 参数来临时“扩容”,争取一些排查时间。但这只是权宜之计,绝非根治之法。
- -XX:PermSize=64m:用于设置永久代的初始大小。
- -XX:MaxPermSize=256m:用于设定永久代的最大上限(一般不建议超过512m,否则可能影响GC效率)。
⚠️ 必须警惕的是,这种“扩容止痛法”不能替代真正的代码修复。更大的风险在于,它可能掩盖真实的内存泄漏问题。况且,这套参数在 JDK 7 之后就已经被废弃了,不具备长期使用的兼容性。
根本修复:避免滥用 String.intern()
说到底,修复的核心在于代码层面。事实上,在绝大多数业务场景里,intern() 都不是一个必需品。下面这几个方案,才是更安全、更可控的替代选择:
- 字符串比较,请优先使用
.equals()。不要为了追求那一点点引用相等(==)的性能,而引入内存风险。 - 如果确实需要字符串去重或缓存,改用
ConcurrentHashMap来自行管理。它的优势很明显:可控、可清理,甚至能配合弱引用来实现更灵活的内存管理。 - 对于极少数确需使用
intern()的场景(比如极高频率的枚举字符串匹配),务必严格限制其输入范围。例如,只对预先定义好的、有限的字符串白名单调用此方法。 - 一个明确的禁区:严禁在循环体内、日志动态拼接、SQL语句构建等会大量、动态生成字符串的路径中,无条件地调用
intern()。这无异于向永久代“灌水”。
验证与监控建议
修复之后,如何验证效果并持续监控?有几个实用的方法。在上线前,可以通过 JMX 工具或者命令行 jstat -gcpermcapacity 来观察永久代的使用量趋势。此外,在启动参数中加上:
-XX:+PrintGCDetails -XX:+PrintGCTimeStamps
这样,在日志中就能重点关注 Full GC 是否被频繁触发,以及 PermGen 的使用率是否还在持续攀升。这些数据,是判断修复是否彻底、系统是否健康的关键指标。
Windows 10 是一款微软推出的经典操作系统,拥有硬件兼容性与多任务处理能力。它更偏向把系统状态查看和常用调节动作放在一起,适合需要持续观察和微调设备状态的场景。
极度公式是一款跨平台专业LaTeX公式识别编辑软件,支持OCR公式识别和多平台编辑。和使用说明,避免使用,享受完整功能与稳定支持。做扫描整理、文字提取和表格转换时,它能把识别后的处理步骤接得更顺,资料录入这类场景会省下不少时间。
















