我在网站上阅读了这个问题java 内存池是如何划分的?我想知道“字符串常量池”属于这些扇区中的哪一个?
池中的文字是否也String
曾被 GC 处理过?
该方法从池中返回文字intern()
的基本链接。String
如果池确实被 GCed,那么它不会对字符串池的想法适得其反吗?将再次创建新的String
文字以使 GC 无效。
(假设池中只存在一组特定的文字,它们永远不会过时,迟早会再次被需要)
我在网站上阅读了这个问题java 内存池是如何划分的?我想知道“字符串常量池”属于这些扇区中的哪一个?
池中的文字是否也String
曾被 GC 处理过?
该方法从池中返回文字intern()
的基本链接。String
如果池确实被 GCed,那么它不会对字符串池的想法适得其反吗?将再次创建新的String
文字以使 GC 无效。
(假设池中只存在一组特定的文字,它们永远不会过时,迟早会再次被需要)
据我所知,字符串文字最终出现在非堆 JVM 内存的“Perm Gen”部分。Perm Gen 空间仅在 Full GC 运行期间检查(而不是 Partials)。
在早期的 JVM 中(我承认我必须查一下,因为我不确定),字符串池中的字符串文字从未被GC 处理过。在较新的 JVM 中,WeakReferences用于引用池中的字符串,因此实习字符串实际上可以进行 GC,但仅在完全垃圾收集期间。
阅读 String.intern() 的 JavaDoc 并没有给出实现的提示,但是根据这个页面,实习字符串由弱引用保存。这意味着如果 GC 检测到除了包含实习字符串的存储库之外没有对实习字符串的引用,则允许收集它们。当然,这对外部代码是透明的,因此除非您使用自己的弱引用,否则您永远不会知道垃圾收集。
字符串池
字符串池(有时也称为字符串规范化)是用一个共享的字符串对象替换多个具有相同值但不同标识的字符串对象的过程。您可以通过保留自己的地图(根据您的要求可能使用软或弱引用)并将地图值用作规范化值来实现此目标。或者您可以使用 JDK 提供给您的 String.intern() 方法。
在 Java 6 中使用 String.intern() 时,许多标准都禁止使用,因为如果池失控,很可能会出现 OutOfMemoryException。字符串池的 Oracle Java 7 实现发生了很大变化。您可以在 http://bugs.sun.com/view_bug.do?bug_id=6962931和 http://bugs.sun.com/view_bug.do?bug_id=6962930中查找详细信息。
Java 6 中的 String.intern()
在过去的美好时光里,所有的实习字符串都存储在 PermGen 中——堆的固定大小部分,主要用于存储加载的类和字符串池。除了显式内嵌的字符串,PermGen 字符串池还包含您程序中之前使用的所有文字字符串(这里使用了重要的词——如果从未加载/调用过类或方法,则不会加载其中定义的任何常量)。
Java 6 中这种字符串池的最大问题是它的位置——PermGen。PermGen 的大小是固定的,不能在运行时扩展。您可以使用 -XX:MaxPermSize=96m 选项进行设置。据我所知,默认 PermGen 大小在 32M 到 96M 之间变化,具体取决于平台。您可以增加它的大小,但它的大小仍然是固定的。这种限制需要非常小心地使用 String.intern——你最好不要使用这种方法来实习任何不受控制的用户输入。这就是为什么在 Java 6 时代字符串池主要是在手动管理的映射中实现的。
Java 7 中的 String.intern()
Oracle 工程师对 Java 7 中的字符串池逻辑进行了极其重要的更改——将字符串池重新定位到堆中。这意味着您不再受单独的固定大小内存区域的限制。所有字符串现在都位于堆中,就像大多数其他普通对象一样,这允许您在调整应用程序时仅管理堆大小。从技术上讲,仅此一项就足以成为重新考虑在 Java 7 程序中使用 String.intern() 的充分理由。但还有其他原因。
字符串池值被垃圾收集
是的,如果您的程序根目录中没有对它们的引用,JVM 字符串池中的所有字符串都可以进行垃圾回收。它适用于所有讨论过的 Java 版本。这意味着如果您的实习字符串超出范围并且没有其他对它的引用 - 它将从 JVM 字符串池中被垃圾收集。
有资格进行垃圾收集并驻留在堆中,JVM 字符串池似乎是您所有字符串的正确位置,不是吗?理论上这是真的——未使用的字符串将从池中被垃圾收集,使用的字符串将允许您节省内存,以防万一您从输入中获得相等的字符串。似乎是一个完美的内存节省策略?几乎如此。在做出任何决定之前,您必须知道字符串池是如何实现的。
字符串,即使它们是不可变的,仍然像 Java 中的任何其他对象一样。对象是在堆上创建的,字符串也不例外。所以,Strings that are part of the "String Literal Pool" still live on the heap, but they have references to them from the String Literal Pool.
更多请参考此链接
`http://www.javaranch.com/journal/200409/ScjpTipLine-StringsLiterally.html`
新编辑:
public class ImmutableStrings
{
public static void main(String[] args)
{
String one = "someString";
String two = new String("someString");
one = two = null;
}
}
就在 main 方法结束之前,有多少对象可用于垃圾回收?0? 1?2?
答案是 1。与大多数对象不同,字符串文字总是从字符串文字池中引用它们。这意味着它们始终具有对它们的引用,因此没有资格进行垃圾收集。
我们的局部变量,一个或两个,都没有引用我们的 String 对象,仍然有来自 String Literal Pool 的引用。因此,该对象不适合进行垃圾回收。通过使用 intern() 方法始终可以访问该对象
String
文字不会在运行时创建到池中。我不确定他们是否获得了 GC,但我怀疑他们没有这样做有两个原因: