JDK 6 中 intern() 将字符串复制到永久代常量池并返回新地址;JDK 7+ 则在堆中查找并直接返回已有对象引用,基于 equals() 匹配,复用更高效。

排查 String.intern() 在 JDK 6 和 JDK 7+ 的行为差异,关键不是看代码写法是否一样,而是观察运行时对象引用关系、内存区域归属和 GC 表现。下面从实操角度给出可验证、可复现的排查路径。
看 == 比较结果是否变化
这是最直接的判断依据。用动态构造的字符串(非字面量)调用 intern() 后与原对象做 == 判断:
- JDK 6:new String("ab") + new String("c") → .intern() 返回的对象和原对象地址一定不同,== 恒为 false
- JDK 7+:同上操作,若该字符串此前未在常量池出现过,== 很可能为 true(前提是堆中对象未被 GC)
- 注意避开预加载字符串(如 "java"、"class" 等),它们在 JVM 启动时已进常量池,无论哪个版本 intern() 都只返回已有引用
查 JVM 内存参数与 OOM 类型
运行时异常类型能快速定位底层区域:
Java Maven 项目审查工作流的通用输入处理。当 Java Maven 项目以 ZIP压缩包或 GitLab 仓库 URL 形式提供且需要...时使用。
- 抛出 java.lang.OutOfMemoryError: PermGen space → 基本确定是 JDK 6 或开启了 -XX:PermSize 的旧版 JDK 7(极少见)
- 抛出 java.lang.OutOfMemoryError: Java heap space 或老年代 GC 频繁 → 更倾向 JDK 7+,说明 intern() 正在往堆里存引用,推高堆压力
- 可通过 jstat -gc <pid> 观察 Metaspace(JDK 8+)或 Perm 区使用率,确认常量池所在区域
用 JVM 工具验证字符串归属位置
借助诊断工具确认对象实际内存分布:
立即学习“Java免费学习笔记(深入)”;
- 用 jmap -histo:live <pid> 查看字符串实例数量,再结合 -dump:format=b,file=heap.hprof 抓堆快照
- 用 JProfiler 或 VisualVM 打开 dump 文件,筛选 String 对象,观察其 classloader 和内存区域标签:JDK 6 中 intern 出的对象会标为 “Perm Gen”;JDK 7+ 全部显示在 “Heap” 下
- 对同一字符串调用 intern() 前后,对比其 identity hash code(System.identityHashCode())是否改变:JDK 6 改变(新对象),JDK 7+ 不变(复用原对象)
检查 JDK 版本与启动参数组合
有些行为看似“版本不符”,实为配置导致:
- 确认真实 JDK 版本:java -version,注意区分 OpenJDK / Oracle / Alibaba Dragonwell 等实现
- JDK 7u40+ 默认启用 G1 GC,而 G1 对字符串常量池的处理更敏感;某些定制 JDK 可能回退常量池位置
- 留意是否设置了 -XX:StringTableSize=N,该参数影响 intern() 查表性能,在 JDK 7+ 中可调大缓解哈希冲突,JDK 6 中无效

















