Java字符串池和堆存储

示例

像许多Java对象一样,所有 String实例(甚至是文字)都在堆上创建。当JVMString在堆中找到没有等效引用的文字时,JVM在堆上创建一个对应的String实例,并且还将对新创建String实例的引用存储在字符串池中。对同一String文字的任何其他引用都将替换String为堆中先前创建的实例。

让我们看下面的例子:

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

        //所有三个字符串都是等效的
        System.out.println(a.equals(b) && b.equals(c));

        //尽管只有a和b引用相同的堆对象
        System.out.println(a == b);
        System.out.println(a != c);
        System.out.println(b != c);
    }
}

上面的输出是:

true
true
true
true

当我们使用双引号创建一个String时,它将首先在String池中查找具有相同值的String,如果发现它只是返回引用,否则它将在池中创建一个新String,然后返回引用。

但是,使用new运算符,我们强制String类在堆空间中创建一个新的String对象。我们可以使用intern()方法将其放入池中,或从具有相同值的字符串池中引用其他String对象。

字符串池本身也在堆上创建。

Java SE 7

在Java 7之前,String 文字是存储在的方法区域中的运行时常量池中的PermGen,其大小是固定的。

字符串池也位于中PermGen。

Java SE 7

RFC:6962931

在JDK 7中,不再将永久字符串分配给Java堆的永久代,而是分配给Java堆的主要部分(称为年轻代和旧代),以及由应用程序创建的其他对象。 。此更改将导致更多数据驻留在主Java堆中,而永久生成中的数据更少,因此可能需要调整堆大小。由于此更改,大多数应用程序只会看到相对较小的堆使用差异,但是加载许多类或大量使用该方法的大型应用程序将看到更大的差异。String.intern()