如果我使用String.intern()来提高性能,因为我可以使用“==”来比较实习字符串,我会遇到垃圾收集问题吗?实习字符串的垃圾收集机制与普通字符串有何不同?
答案 0 :(得分:19)
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()
来比较字符串,您将活得更长久,更快乐。
答案 1 :(得分:11)
实际上,这不是垃圾收集优化,而是字符串池优化。
当你调用String.intern()
时,用你的基本引用(第一次遇到这个字符串的引用,或者如果它还不知道的那个引用)替换对你的初始字符串的引用。
但是,一旦你的字符串在应用程序中不再使用它,它将成为一个垃圾收集器问题,因为interned字符串池是String类的静态成员,永远不会被垃圾收集。
根据经验,我认为更喜欢从不使用这个实习方法,让编译器只将它用于常量字符串,这些声明如下:
String myString = "a constant that will be interned";
这是更好的,从某种意义上说,它不会让你做错误的假设==
可以工作,但不会。
此外,事实是String.equals
潜在地调用==
作为优化,确保在引擎盖下使用实习字符串优化。这是另一个证据==
永远不会用于字符串。
答案 2 :(得分:6)
This article提供了完整的答案。
在java 6中,字符串池驻留在PermGen中,因为java 7中的字符串池驻留在堆内存中。
手动实习的字符串将被垃圾收集。
如果卸载定义它们的类,则字符串文字将仅被垃圾收集。
字符串池是一个固定大小的HashMap,在java 6和早期版本的java 7中很小,但是自java 7u40以来增加到60013。
可以使用 -XX:StringTableSize =&lt; new size&gt; 进行更改,并使用 -XX:+ PrintFlagsFinal java选项进行查看。
答案 3 :(得分:0)
请阅读:http://satukubik.com/2009/01/06/java-tips-memory-optimization-for-string/
我可以从您的信息中得出的结论是:您实施了太多字符串。如果你真的需要实习这么多String来进行性能优化,增加烫发内存,但如果我是你,我会先检查如果真的需要那么多实习生字符串。