StringTableSize影响性能因底层为固定大小哈希表,桶数过少导致哈希冲突加剧、链表变长,使intern()查找从O(1)退化为O(n);默认JDK7/8为60013,JDK6为1009,最小值1009。

StringTableSize 为什么影响性能
StringTable 底层是固定大小的哈希表(HashTable),由数组(桶)和链表组成。桶数量即 StringTableSize,决定了哈希空间的“宽度”。桶太少,大量字符串哈希后挤进少数桶里,链表变长,每次 intern() 都得遍历链表比对,查找耗时飙升;桶足够多,字符串分布更均匀,冲突减少,平均查找接近 O(1)。
默认值在 JDK 7/8 中是 60013,JDK 6 是 1009。最小允许值为 1009,不能设为小于该值的数。
怎么判断是否需要调大 StringTableSize
当应用满足以下任一条件时,建议关注并测试调优:
- 频繁调用
String.intern()(如解析大量重复文本、用户地址、URL 路径、日志字段等) - JVM 启动参数中开启
-XX:+PrintStringTableStatistics后,发现 “Number of entries” 接近或超过 “Number of buckets” 的 1.5 倍以上 - 监控到
intern()调用耗时明显上升,或 GC 日志中出现与字符串处理相关的延迟毛刺 - 使用 JVisualVM 或 JFR 观察到 StringTable 占用内存高且链表深度普遍 ≥5
如何设置和验证效果
通过 JVM 参数直接指定桶数量:
-XX:StringTableSize=200000
设置后需配合统计开关验证效果:
-XX:+PrintStringTableStatistics -XX:+PrintGCDetails
运行程序后观察控制台输出,重点关注三组数字:
- Number of buckets:实际桶数(应与你设置的值一致)
- Number of entries:已存入的唯一字符串个数
- Mean bucket length:平均链表长度(理想值 ≤2;若 >4 则说明冲突较重)
例如:设为 200000,存入 48 万个单词,entries 约 48w,则平均每个桶仅约 2.4 个字符串,冲突大幅缓解。
调优注意事项与常见误区
不是越大越好——过大的 StringTableSize 会浪费内存(空桶也占数组空间),且初始化时间略增;但相比性能损失,适度冗余更值得。
注意版本差异:
- JDK 6:固定 1009,不可调;若字符串多,intern 性能天然受限
- JDK 7+:支持动态设置,推荐从 10w~50w 区间起步压测,根据实际 entries 数量按 2~3 倍设定
搭配 intern() 使用才有意义:只调大 StringTableSize,却不主动调用 intern 或不产生大量重复字符串,不会带来收益。
串池本身在堆中(JDK 7 起),所以 StringTable 扩容不涉及永久代/Metaspace,但会占用堆内空间——需确保堆内存充足,避免因扩容间接诱发 GC 压力。
















