我正在开发一个有很多重复字符串的应用程序,我的任务是消除它们以减少内存使用量。我的第一个想法是使用 String.intern
来保证只有一个字符串引用存在。它有效地减少了堆内存,但它增加了太多的 PermGen;事实上,由于有许多字符串只声明一次,因此应用程序使用的内存总量实际上增加了。
在搜索了另一个想法之后,我找到了这种方法:https://stackoverflow.com/a/725822/1384913。
它与 String.intern 发生了同样的事情:字符串使用量减少了,但我保存的内存正在WeakHashMap
和WeakHashMap$Entry
类中使用。
有没有一种有效的方法可以为每个字符串维护一个引用,该字符串不会花费与我正在恢复的相同数量的内存?
我找到了WeakHashMap
的替代方案:Eclipse JDT库提供的WeakHashSet
。它的行为与WeakHashMap
相同,但占用的内存更少。此外,您只需要调用该方法add
,如果 String 尚不存在,它将在集合中添加 String,否则返回现有的字符串。
我唯一不喜欢的是它不使用泛型,迫使开发人员强制转换对象。我的intern
方法非常简单,如您在下面看到的:
WeakHashSet
声明 :
private static WeakHashSet stringPool = new WeakHashSet(30000); //30 thousand is the average number of Strings that the application keeps.
和实习方法:
public static String intern(String value) {
if(value == null) {
return null;
}
return (String) stringPool.add(value);
}
为什么不使用 StringBuilder/StringBuffer 类而不是 String。使用此类的实例,您始终可以使用具有不同值的同一实例。- 安库尔
在类似的情况下,只要有可能,我就将字符串常量重构为枚举。这样,您将获得两个好处:
- 枚举实例是单例实例,因此不会遇到内存问题
- 使用字符串时没有拼写错误。
缺点:
- 大量的工作,犯错误的可能性有无限,如果你没有足够的测试用例
- 有时这并非微不足道,例如,当您必须与第三方库交互时,您不能只是编辑......
- 如果这些是运行时确定的,而不是编译时,那么简直是不行的......