【发布时间】:2013-09-30 08:33:28
【问题描述】:
案例一:
String str = "StackOverFlow"; String str1 = "StackOverFlow"; if(str==str1){ System.out.println("equal");//prints equal }案例 2:
String str = "StackOverFlow"; String str1=str.intern(); if(str==str1){ System.out.println("equal");//prints equal }
跟进问题:
我想知道对于第一种情况JVM是否在内部调用
intern()并将str的引用分配给str1?在第一种情况下两个引用如何相等?
第一种情况是否意味着每当您声明像
String str = "StackOverFlow";这样的字符串时,它都会像intern()方法一样添加到字符串池中?String str = "StackOverFlow";和intern()使用的字符串池是否分配在堆外?如果是,具体在哪里?
问题4的答案如下:
在 Java 6 及更早版本中,实习字符串也存储在永久代中。在 Java 7 中,内部字符串存储在主对象堆中。
文档是这样写的:
在 JDK 7 中,interned 字符串不再分配在永久 Java 堆的生成,而是分配在主堆中 Java 堆的一部分(称为年轻代和年老代),沿 与应用程序创建的其他对象。这种变化将 导致更多的数据驻留在主 Java 堆中,而更少的数据在 永久代,因此可能需要堆大小为 调整。大多数应用程序只会看到相对较小的差异 由于此更改,堆使用量增加,但加载的应用程序更大 许多类或大量使用
String.intern()方法会看到 更显着的差异。
更多详情:
Java 6 中的 String.intern()
在那些美好的过去,所有的实习字符串都存储在 PermGen 中 – 堆的固定大小部分,主要用于存储加载的类 和字符串池。除了显式实习字符串,PermGen 字符串 pool 还包含您程序中之前使用的所有文字字符串 (这里使用了重要的词——如果一个类或方法从未被 加载/调用,其中定义的任何常量都不会被加载)。
The biggest issue with such string pool in Java 6 was its location – the PermGen. PermGen has a fixed size and can not be expanded at运行时。您可以使用 -XX:MaxPermSize=96m 选项进行设置。据我所知 知道,默认 PermGen 大小在 32M 和 96M 之间变化,具体取决于 该平台。你可以增加它的大小,但它的大小仍然是 固定的。这种限制需要非常小心地使用 String.intern – 你最好不要使用这种方法来实习任何不受控制的用户输入。 这就是为什么在 Java 6 时代的字符串池主要是在 手动管理的地图。
Java 7 中的 String.intern()
Oracle 工程师对字符串进行了极其重要的更改 Java 7 中的池化逻辑——字符串池被重新定位到堆中。 这意味着您不再受限于单独的固定尺寸 内存区。现在所有字符串都位于堆中,就像其他大多数字符串一样 普通对象,它允许您只管理堆大小,同时 调整您的应用程序。从技术上讲,仅此一项就足够了 重新考虑在 Java 7 程序中使用 String.intern() 的原因。 但还有其他原因。
【问题讨论】:
-
Java 文字字符串(包含在
".."中的字符串)总是在加载关联的类时隐式地被嵌入。实习一个已经实习过的字符串是无操作的。 -
我猜是因为编译器会自动实习这两个字符串常量。
-
intern()在这种情况下无效。尝试使用编译器,例如使用str2 = new StringBuilder("Stack").append("OverFlow").tostring()。这样,str2需要在运行时构造,并且应该不同于(通过引用等于)str1。
标签: java string memory-management