我知道"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));
}
}
答案 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;不正确:
您实际上是在谈论字符串池。 (常量池是类文件格式的一部分,事情是&#34;由编译器等创建&#34;)
虽然"a"
和"b"
将放在字符串池中,但表达式new String("b")
不会在字符串池中创建(或重用)字符串。它在常规堆中创建一个新的String对象。
第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());
}
}