当前位置: 首页 > 知识库问答 >
问题:

字符串常量池内存扇区和垃圾收集

云鸿祯
2023-03-14

我在网站上读到了这个问题:java内存池是如何划分的?我想知道“字符串常量池”属于这些扇区中的哪一个?

还有池中的字符串文字是否曾经被 GC 化?

intern()方法从池中返回String文字的基链接。

如果池确实被 GC 处理,那么它不会对字符串池的想法适得其反吗?将再次创建新的字符串文本,使 GC 无效。

(假设池中仅存在一组特定的文本,它们永远不会过时,迟早会再次需要它们)

共有3个答案

荀嘉熙
2023-03-14

字符串池

字符串池(有时也称为字符串规范化)是用单个共享字符串对象替换多个具有相同值但不同标识的字符串对象的过程。您可以通过保留自己的映射(根据您的要求,可能有软引用或弱引用)并将映射值用作规范化值来实现这一目标。或者你可以使用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工程师对Java7中的字符串池逻辑进行了极其重要的更改——字符串池被重新定位到堆中。这意味着您不再受单独的固定大小内存区域的限制。现在,所有字符串都与大多数其他普通对象一样位于堆中,这允许您在调整应用程序时仅管理堆大小。从技术上讲,这一点就足以成为重新考虑使用String的理由。在Java 7程序中使用intern()。但还有其他原因。

字符串池值被垃圾回收

是的,如果没有程序根对JVM字符串池中的所有字符串的引用,那么这些字符串都可以进行垃圾收集。它适用于所有讨论的Java版本。这意味着,如果您的实习生字符串超出范围,并且没有其他对它的引用,那么它将从JVM字符串池中被垃圾收集。

由于有资格进行垃圾收集并驻留在堆中,JVM字符串池似乎是所有字符串的合适位置,不是吗?理论上这是正确的——未使用的字符串将从池中被垃圾收集,使用过的字符串将允许您节省内存,以防您从输入中获得相同的字符串。似乎是一个完美的内存节省策略?几乎如此。在做出任何决定之前,您必须知道字符串池是如何实现的。

来源。

杜英范
2023-03-14

读取JavaDoc for String。intern()没有给实现提供提示,但根据本页,实例化的字符串由弱引用保存。这意味着,如果GC检测到除了保存内部字符串的存储库之外,没有对内部字符串的引用,则允许收集它们。当然,这对外部代码是透明的,所以除非您使用自己的弱引用,否则您永远不会知道垃圾收集。

孟杰
2023-03-14

据我所知,字符串文字最终出现在非堆JVM内存的“Perm Gen”部分。Perm Gen空间仅在完整的GC运行期间进行检查(而不是部分检查)。

在早期的JVM中(我承认我不得不查一下,因为我不确定),字符串池中的字符串文字从来没有被GC'ed过。在较新的JVM中,WeakReferences被用来引用池中的字符串,所以被保留的字符串实际上可以被GC'ed,但只是在完全垃圾收集期间。

 类似资料:
  • 每个人都知道这一点。Net framework字符串对象直接存储在堆内存中 我只是想弄清楚里面是否有保留的记忆。Net字符串框架。在java中,有一个为字符串保留的内存,称为SCMP(字符串常量内存池),在这里字符串被初始化和垃圾收集,就像堆内存中的其他对象一样。

  • 问题内容: 我正在阅读有关垃圾收集的信息,当我搜索字符串文字垃圾收集时,搜索结果令人困惑。 我需要澄清以下几点: 如果在编译时将字符串定义为文字字符串,那么是否会对其进行垃圾回收? 如果使用实习方法,那么它会被垃圾回收吗?在第1点中,它也将与文字区别对待。 有人提到只有在卸载类时才会对文字进行垃圾回收吗?是否有道理,因为我认为永远不会卸课。 问题答案: 如果在编译时将字符串定义为文字字符串,那么是

  • 问题内容: 探索了Java的字符串内部结构之后,我对所谓的“烫发空间”感到困惑。我最初对它的理解是,它包含 字面值 以及此问题中说明的类元数据。 我还阅读了有关该方法的信息,并将其放入字符串池,返回对该方法唯一实例的引用。据我了解,这是与存在于JVM的perm空间中的String字符串相同的字符串池。在我看来,“烫发空间”是不可能修改的(毕竟它是永久的,是吗?)。但是,然后我发现了这个问题,EJP

  • 在爪哇 使用新运算符创建的对象将存储在堆内存中 我正在运行下面的代码来检查hashcode。 代码的输出是 这两个对象都是使用新运算符和字符串文字创建的,并相应地存储在不同的位置堆内存和字符串常量池中。那么内存地址是如何相同的。 如果我错了,请解释一下这个概念

  • 1.1 程序计数器 JVM 支持多线程同时执行,每个线程都有自己的程序计数器,线程正在执行 Java 代码,则存放正在执行的指令地址,如果正在执行 C 代码(本地方法),则为空。 1.2 虚拟机栈 线程私有,每个方法创建一个栈帧,用于存储局部变量表(this、参数列表、局部变量)、操作数栈(将下一个指令入栈,执行时出栈)、动态链接、方法出口等信息。方法从调用到执行完成对应栈帧的入栈到出栈,线程内串

  • 如这些问题中所述:问题1 在以下情况下,JVM将创建一个新的字符串对象,而不是使用字符串池中的现有对象: 然而,在阅读了下面两个类似的陈述之后,我有一个疑问。 从SCJP准备书: 当编译器遇到字符串文字时,它会检查池中是否已经存在相同的字符串。如果找到匹配项,对新文本的引用将指向现有的String,并且不会创建新的String文本对象。 来自JavaRanch: 在本例中,由于关键字“new”,我