String interning是否导致String在堆和本机内存中?

时间:2015-07-02 03:40:30

标签: java string memory-management jvm jvm-hotspot

这是String #intern的javadoc:

String ref1 = "ref";
String ref2 = ref1.intern();

假设我有下一个代码:

{{1}}

在初始化ref的时候,ref1是否仍然在堆中。我问,因为如果它是没有删除原始引用的实习字符串将加倍java进程使用的RSS内存。

1 个答案:

答案 0 :(得分:2)

如果我们考虑您的示例,是的,ref1仍在堆中,但因为ref1ref2都指向相同的实例。您使用字符串文字初始化ref1,字符串文字自动实习as described here

  

此外,字符串文字始终引用类String的相同实例。这是因为字符串文字 - 或者更常见的是作为常量表达式(§15.28)的值的字符串 - 被“实例化”以便使用String.intern方法共享唯一实例。

因此,没有双内存使用(如果你不认为字符串存在于保存类ConstantPool的内容和所有类结构信息的单独内存区域中。)

要详细解释实习如何实际工作,请参阅此示例:

public class Intern{
    public static void main(String... args){
        String str1="TestStr";
        String str2="TestStr";
        System.out.println("1. "+(str1==str2));
        String str3=str1.intern();
        System.out.println("2. "+(str1==str3));
        String str4=new String("TestStr");
        System.out.println("3. "+(str1==str4));
        String str5=str4.intern();
        System.out.println("4. "+(str4==str5));
        System.out.println("5. "+(str1==str5));
    }
}

你会得到这个输出:

1. true

从常量池加载的字符串会自动插入到字符串池中,结果为true,两个实例都引用相同的实体对象。

2. true

str3指的是已经实习的字符串实例。

3. false

str4是一个新实例,与之前的实例无关。

4. false

一次性str4实例不指向自字符串池开头以来存在的同一对象。

5. true

str5按预期指向我们的实习字符串。

值得注意的是,在Java 7(Oracle实现)之前,实习字符串存储在PermGem中(因为Java 8不再存在),但是从那个版本开始,它们已经被移动到堆中。因此,在大量使用实习功能时,可能会出现使用较旧版本的JVM特有内存问题。

有关如何在不同版本中管理实习字符串的其他信息,请查看此版本post