什么时候在java中对字符串进行垃圾回收

2022-08-31 12:48:03

在Java中,当一个对象没有实时引用时,它就有资格进行垃圾回收。现在,对于字符串,情况并非如此,因为字符串将进入字符串池,JVM将使对象保持活动状态以供重用。所以这意味着一旦创建了字符串,“永远不会”被垃圾回收?


答案 1

现在,对于字符串,情况并非如此,因为字符串将进入字符串池,JVM将使对象保持活动状态以供重用。所以这意味着一旦创建了字符串,“永远不会”被垃圾回收?

首先,只有字符串文本(请参阅注释)才能自动滞留/添加到字符串池中。 应用程序在运行时创建的对象不会被暂存...除非应用程序显式调用 。StringString.intern()

其次,实际上字符串池中垃圾回收对象的规则与其他对象的规则相同:实际上是所有对象。如果 GC 发现它们无法访问,它们将被垃圾回收。String

实际上,与字符串文本对应的对象通常不会成为垃圾回收的候选对象。这是因为在使用文本的每个方法的代码中都有对对象的隐式引用。这意味着只要可以执行该方法,就可以访问 。StringStringString

但是,情况并非总是如此。如果在动态加载的类中定义了字符串文本(例如 using ),则可以安排卸载该类。如果发生这种情况,则与文本对应的对象可能无法访问,并且最终可能被GC'ed。Class.forName(...)String

另请参阅:何时以及如何在Java中对类进行垃圾回收?


笔记:

  1. 字符串文本(JLS 3.10.5)是出现在Java源代码中的字符串;例如:

      "abc"            // string literal
      new String(...)  // not a string literal
    
  2. 也可以暂存由(编译时)常量表达式 (JLS 15.28) 的计算生成的字符串。

       "abc" + 123      // this is a constant expression
    
  3. 严格来说,并非所有字符串文本都会被暂存:

    • 如果 String 文本仅作为常量表达式的子表达式出现在源代码中,则该文本可能不会以任何形式出现在“.class”文件中。这样的文字不会被拘禁,因为它在运行时不存在。

    • 在 Java 9+ 中,涉及非编译时常量的文字和值的字符串串联的处理方式可能会有所不同。现在,在字节码编译器的选项中,字符串串联如下所示:

       int x = 42;   // not a compile time constant
       String s = "prefix " + x + " suffix";
      

      可能会导致像下面这样的字符串常量被暂留:

       "prefix \1 suffix"
      

      在运行时,上述字符串常量用作生成动态串联方法的“配方”。原始字符串文本(即 和 ) 不会变成被拘禁的字符串对象。"prefix "" suffix"

      感谢@Holger指出这一点。有关更多详细信息,请参阅 JEP 280javadocStringConcatFactory

  4. 在Java 7之前,字符串池位于PermGen中。对于某些版本的 Java,如果选择了 CMS 收集器,则默认情况下不会启用 PermGen 的垃圾回收。但是CMS从来都不是默认的收集器,并且有一个标志可以通过CMS启用PermGen收集。(没有人应该再为Java 6及更早版本开发代码了。


答案 2

你是对的;实习生池中的字符串永远不会被GC'd。

但是,大多数字符串上没有被拘留。
字符串文本被暂存,传递给的字符串被暂存,但所有其他字符串都不会被暂存,并且可以正常地进行 GC。。String.intern()