在Java中,当一个对象没有实时引用时,它有资格进行垃圾回收。现在在字符串的情况下,情况并非如此,因为字符串将进入字符串池,JVM将使对象保持活动状态以便重用。 这意味着创建的字符串“永远不会”被垃圾收集?
答案 0 :(得分:66)
现在在字符串的情况下,情况并非如此,因为字符串将进入字符串池,JVM将使对象保持活动状态以便重用。这意味着创建的字符串“永远不会”被垃圾收集?
首先,仅字符串文字(请参阅注释)会自动实习/添加到字符串池中。应用程序在运行时创建的String
个对象不会被实现...除非您的应用程序显式调用String.intern()
。
其次,实际上字符串池中垃圾收集对象的规则与其他String
对象的规则相同:实际上是所有对象。如果它们无法访问,它们将被垃圾收集。
实际上,与字符串文字对应的String
对象通常不会成为垃圾回收的候选对象。这是因为在使用该文字的每个方法的代码中都存在对String
对象的隐式引用。这意味着只要方法可以执行,String
就可以到达。
但是,这不是总是的情况。如果在动态加载的类中定义了字符串文字(例如,使用Class.forName(...)
),则可以安排该类卸载。如果发生这种情况,则对应于文字的String
对象可能然后无法访问,并且最终可能是GC。
注意:
字符串文字(JLS 3.10.5)是在Java源代码中出现的字符串; e.g。
"abc" // string literal
new String(...) // not a string literal
通过评估(编译时)常量表达式(JLS 15.28)生成的字符串也可以实现。
严格地说,并非所有字符串文字都被实习。如果字符串文字仅作为常量表达式的子表达式出现在源代码中,则文字可能不会以任何形式出现在“.class”文件 中。这样的文字不会被实习,因为它不会在运行时存在。
答案 1 :(得分:8)
你是对的;实习池中的字符串永远不会是GC。
但是,大部分字符串都没有实习。
字符串文字被实习,并且传递给String.intern()
的字符串被实习,但所有其他字符串都没有实习并且可以正常进行GC。
答案 2 :(得分:1)
字符串池中的字符串对象将不会被垃圾回收。如果您在程序执行过程中未引用其他String对象,则将对其进行垃圾回收。
您可能会问哪些字符串对象进入字符串池。字符串池中的对象是:
编译时文字(例如String s1 = "123";
)
运行时中的内部字符串对象(例如String s2 = new String("test").intern();
)
s1
和s2
都引用了字符串池中的字符串对象。
任何在运行时创建但未被阻止的对象都将充当普通对象并驻留在堆内存中。这些对象可以被垃圾收集。
例如:String s3 = s1 + s2;
在这里,s3
引用了一个字符串对象,该字符串对象与其他对象(不在字符串池中)一起位于堆内存中。
答案 3 :(得分:-1)
在 Java 7 之前,字符串池驻留在永久代空间中。所以字符串文字永远不会被垃圾收集(这也多次导致内存不足问题) Java 7之后,字符串池被放到堆空间中,由JVM进行垃圾回收。它还减少了在 JVM 中出现内存不足问题的机会。