String.intern()的垃圾收集行为

时间:2010-03-12 09:14:14

标签: java performance string garbage-collection

如果我使用String.intern()来提高性能,因为我可以使用“==”来比较实习字符串,我会遇到垃圾收集问题吗?实习字符串的垃圾收集机制与普通字符串有何不同?

4 个答案:

答案 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来进行性能优化,增加烫发内存,但如果我是你,我会先检查如果真的需要那么多实习生字符串。