“a”vs' new String(“b”)'在常量池(JVM JDK 6)(渴望真相)

时间:2015-12-25 11:58:10

标签: java string exception jvm

我知道"a"new String("b")都会在常量池中创建"a""b"

但为什么下面的程序不会抛出outOfMemoryError

new String("b")是否在常量池中不创建任何内容?

List<String> s = new ArrayList<String>();
// -XX:PermSize=5M
// -XX:MaxPermSize=5M
// why no oom:pergen space throw???? "i" isn't in constant pool????
for (;;) {
    for (int i = 0; i < 1000000; i++) {
        s.add(new String("" + i));
    }
}

2 个答案:

答案 0 :(得分:4)

new String(...)正在正常堆中创建对象,因此限制永久生成不会触发OOME。 使用旧版本的java,您可以通过在结果字符串上调用.intern()来模拟它,但即使最近也发生了变化(详情请参阅http://java-performance.info/string-intern-in-java-6-7-8/)。

在java 8中,烫发生成似乎完全消失了 http://www.infoq.com/articles/Java-PERMGEN-Removed 因此,除非您专门针对旧版本,否则尝试查找其限制可能会适得其反,而是尝试了解Metaspace。

答案 1 :(得分:1)

  

我知道"a"new String("b")都会在常量池中创建"a""b"

你的知识&#34;不正确:

  1. 您实际上是在谈论字符串池。 (常量池是类文件格式的一部分,事情是&#34;由编译器等创建&#34;)

  2. 虽然"a""b"将放在字符串池中,但表达式new String("b")不会在字符串池中创建(或重用)字符串。它在常规堆中创建一个新的String对象。

  3. 第2点解释了为什么你不能通过使用new String(...)创建字符串来填充permgen(在它存在的JVM上)。

    如果要强制字符串进入字符串池,则需要使用String.intern。如果您将代码修改为以下内容,则应该能够在permgen堆中触发OOME(Java 7及更早版本):

    for (;;) {
        for (int i = 0; i < 1000000; i++) {
            s.add((new String("" + i)).intern());
        }
    }