字串池和堆儲存

像許多 Java 物件一樣,所有 String 例項都是在堆上建立的,甚至是文字。當 JVM 發現在堆中沒有等效引用的 String 文字時,JVM 在堆上建立相應的 String 例項,並且它還儲存對 String 池中新建立的 String 例項的引用。對同一 String 文字的任何其他引用都將替換為堆中先前建立的 String 例項。

我們來看下面的例子:

class Strings
{
    public static void main (String[] args)
    {
        String a = "alpha";
        String b = "alpha";
        String c = new String("alpha");

        //All three strings are equivalent
        System.out.println(a.equals(b) && b.equals(c));

        //Although only a and b reference the same heap object
        System.out.println(a == b);
        System.out.println(a != c);
        System.out.println(b != c);
    }
}

以上的輸出是:

true
true
true
true

StackOverflow 文件 當我們使用雙引號建立一個 String 時,它首先在 String 池中查詢具有相同值的 String,如果發現它只返回引用,否則它在池中建立一個新 String,然後返回引用。

但是,使用 new 運算子,我們強制 String 類在堆空間中建立一個新的 String 物件。我們可以使用 intern() 方法將它放入池中或從具有相同值的字串池中引用其他 String 物件。

字串池本身也在堆上建立。

Version < Java SE 7

在 Java 7 之前,String 文字儲存在 PermGen 的方法區域中的執行時常量池中,該區域具有固定大小。

字串池也位於 PermGen 中。

Version >= Java SE 7

RFC:6962931

在 JDK 7 中,實現的字串不再分配在 Java 堆的永久生成中,而是分配在 Java 堆的主要部分(稱為年輕和舊的代)中,以及應用程式建立的其他物件。此更改將導致更多資料駐留在主 Java 堆中,並且永久生成中的資料更少,因此可能需要調整堆大小。由於這種變化,大多數應用程式只會看到堆使用中的相對較小的差異,但是載入許多類或大量使用 String.intern() 方法的較大應用程式將看到更顯著的差異。