如果我使用 String.intern() 来提高性能,因为我可以使用“==”来比较实习字符串,我会遇到垃圾收集问题吗?内部字符串的垃圾回收机制与普通字符串有何不同?
String.intern()
管理一个内部的、本机实现的池,它具有一些与 GC 相关的特殊功能。这是旧代码,但如果重新实现,它将使用 java.util.WeakHashMap
。弱引用是一种保留指向对象的指针而不阻止其被收集的方法。对于统一池(例如实习字符串)来说正是正确的选择。
可以使用以下 Java 代码演示驻留字符串是否被垃圾回收:
public class InternedStringsAreCollected {
public static void main(String[] args)
{
for (int i = 0; i < 30; i ++) {
foo();
System.gc();
}
}
private static void foo()
{
char[] tc = new char[10];
for (int i = 0; i < tc.length; i ++)
tc[i] = (char)(i * 136757);
String s = new String(tc).intern();
System.out.println(System.identityHashCode(s));
}
}
此代码创建 30 次相同的字符串,每次都会对其进行实习。此外,它还使用
System.identityHashCode()
来显示 Object.hashCode()
在该保留字符串上返回的哈希码。运行时,此代码会打印出不同的整数值,这意味着您不会每次都获得相同的实例。
无论如何,不鼓励使用
String.intern()
。它是一个共享静态池,这意味着它很容易成为多核系统上的瓶颈。使用String.equals()
比较字符串,你会活得更长久、更快乐。
事实上,这不是垃圾收集优化,而是字符串池优化。 当您调用
String.intern()
时,您将对初始字符串的引用替换为其基本引用(第一次遇到该字符串的引用,如果尚不知道则为该引用)。
在 Java 7 之前,内部字符串是在 PermGen 空间中分配的。一旦您的字符串在应用程序中不再使用,这将成为垃圾收集器问题,因为内部字符串池是 String 类的静态成员,并且永远不会被垃圾收集。从 Java 7 开始,驻留字符串分配在 Heap 上并接受垃圾回收。
根据经验,我认为最好从不使用此实习生方法,并让编译器仅将其用于常量字符串,这些常量字符串如下声明:
String myString = "a constant that will be interned";
这更好,从某种意义上说,它不会让你做出错误的假设
==
可以工作,但它不会。
此外,事实是
String.equals
本质上调用 ==
作为优化,确保在幕后使用内部字符串优化。这是又一个证据 ==
不应该永远 用于字符串。
这篇文章提供了完整的答案。
在java 6中,字符串池驻留在PermGen中,从java 7开始,字符串池驻留在堆内存中。
手动驻留的字符串将被垃圾收集。
仅当定义字符串文字的类被卸载时,字符串文字才会被垃圾收集。
字符串池是一个固定大小的HashMap,在java 6和java 7早期版本中很小,但从java 7u40开始增加到60013。
可以使用 -XX:StringTableSize=
请阅读:http://satukubik.com/2009/01/06/java-tips-memory-optimization-for-string/
从你的信息中我能得到的结论是:你实习了太多的String。如果你确实需要实习这么多 String 来优化性能,增加 perm gen 内存,但如果我是你,我会先检查是否真的需要这么多实习字符串。