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

时间:2012-06-08 16:13:14

标签: java memory-management garbage-collection

我在网站How is the java memory pool divided?上阅读了这个问题,我想知道这些扇区中的哪一个是"字符串常量池"属于?

池中的String文字是否也得到了GC?

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

如果池确实获得了GCed,那么它对于字符串池的想法是否会适得其反?将再次创建新的String文字,从而使GC无效。

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

5 个答案:

答案 0 :(得分:2)

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

在早期的JVM中(我承认我必须查看它,因为我不确定),字符串池never got GC中的字符串文字。在较新的JVM中,WeakReferences用于引用池中的字符串,因此实际的字符串实际上可以获取GC,但仅限于完全垃圾收集期间。

答案 1 :(得分:1)

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

答案 2 :(得分:1)

字符串合并

  

字符串池(有时也称为字符串规范化)是一种   用相同的值替换几个String对象的过程但是   具有单个共享String对象的不同标识。你可以实现   保持自己的地图(可能是软的)   或弱参考,取决于您的要求)和使用地图   值作为规范化的值。或者您可以使用String.intern()方法   由JDK提供给您。

     

在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字符串   pool还包含程序中先前使用的所有文字字符串   (这里使用的重要词 - 如果一个类或方法永远不会   加载/调用,其中定义的任何常量都不会被加载。

     

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   字符串池似乎是所有字符串的正确位置,不是吗?   理论上确实如此 - 未使用的字符串将被垃圾收集   池,使用的字符串将允许您保存内存以防万一   从输入中获取一个相等的字符串。似乎是一个完美的记忆   储蓄策略?几乎如此。您必须知道字符串池是如何的   在做出任何决定之前实施。

source.

答案 3 :(得分:0)

String文字不会在运行时创建到池中。我不确定他们是否得到了GC,但我怀疑他们不是出于两个原因:

  • 在一般情况下检测文字不再使用时会非常复杂
  • 可能存在一个静态代码段,用于存储性能。其余数据可能围绕它构建,其中边界也是静态的

答案 4 :(得分:0)

尽管字符串是不可变的,但它们仍然是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()方法总是可以访问对象