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

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


答案 1

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()


答案 2

实际上,这不是垃圾回收优化,而是字符串池优化。调用 时,将对初始 String 的引用替换为其基引用(第一次遇到此字符串的引用,如果尚不知道,则替换为此引用)。String.intern()

但是,一旦您的字符串在应用程序中不再有用,它将成为垃圾回收器问题,因为滞留的字符串池是 String 类的静态成员,永远不会被垃圾回收。

根据经验,我认为最好不要使用此terntern方法,并让编译器仅将其用于常量字符串,这些字符串声明如下:

String myString = "a constant that will be interned";

这更好,从某种意义上说,它不会让你做错误的假设,当它不起作用时,它可能会起作用。==

此外,事实是底层调用作为优化,确保在后台使用内部字符串优化。这是永远不应该在字符串上使用的另一个证据。String.equals====