是String.intern()在JDK 6下引发的常量池溢出:OOM日志含“PermGen space”且堆栈出现String.intern(Native Method)或紧邻循环逻辑;jstat显示PermCap数分钟内从30%飙升至95%+不回落;代码中存在分页查询、日志拼接或未去重枚举值等高频误用模式。
直接看异常日志和 jvm 监控数据,就能快速锁定是不是 string.intern() 在 jdk 6 环境下引发的常量池溢出。
看 OOM 异常信息是否带关键线索
发生崩溃时,重点检查日志中是否同时满足以下两点:
- 异常类型明确是
java.lang.OutOfMemoryError: PermGen space - 堆栈里出现
String.intern(Native Method),或者它紧挨着一个循环结构(比如for、while、Stream.forEach)
用 jstat 实时观察永久代使用趋势
在服务还在运行但已开始变慢时,执行命令:
jstat -gcpermcapacity
如果发现 PermCap 使用率在几分钟内从 30% 左右一路飙升到 95% 以上,且几乎不回落,基本可以确认是 intern 持续写入导致的常量池占满。
查代码里有没有高频误用模式
重点扫描这几类典型写法:
- 数据库分页查询中,对每条记录字段无条件调用
rs.getString("xxx").intern() - 日志拼接或 SQL 构建时,先拼出新字符串再
.intern(),例如(prefix + id + suffix).intern() - 从字典表加载状态值等枚举字段,未去重就逐行
intern(),比如 10 万行含 5 种取值,却调用了 10 万次
临时止血和长期修复要点
确认问题后,可先加参数争取排查时间(仅限 JDK 6):
-
-XX:PermSize=128m:设初始大小,避免启动即满 -
-XX:MaxPermSize=384m:上限控制在 512m 以内,防止 GC 效率恶化
根本解决要改代码逻辑:
- 禁用循环内调用
intern() - 改用预加载 + 白名单方式:启动时读取全部可能值 → 去重 → 对有限集合逐个
intern()→ 缓存为Map - 运行时只查缓存,绝不动态生成再入池










