另一个字符串的子字符串是否会阻止父字符串被垃圾回收?

String samplel = "ToBeGarbageCollected"; String sample2 = samplel.substring(0, 1); samplel = null; 

我知道内部的子串将保留原始String的引用。

但是通过将samplel明确定义为null ,sample1和sample2是否可用于垃圾收集?

我记得在某个地方,如果父对象被显式设置为null所有子值都可用于垃圾回收。 这对上述情况有利吗? 我只是好奇这是否是父母子女关系的情景? 如果没有,这会导致sample1sample2可用于垃圾收集吗?

 String samplel = "ToBeGarbageCollected"; String sample2 = new String(samplel .substring(0, 1)); samplel = null; 

首先要说的是垃圾收集不会立即发生。 因此,为任何事物分配null不会/不会导致垃圾回收。 可能做的是使对象变得无法访问 ……这将使其成为未来GC运行中垃圾收集的潜在候选者。


现在来看你的具体例子。

重要说明:以下内容适用于较旧的JVM; 即Java 7更新5及更早版本。 在Java 7 update 6中,他们更改了String.substring()以便目标字符串和生成的子字符串不共享后备数组。 这消除了substring的潜在存储泄漏问题。


substring方法不会在新String中引用原始String。 它实际上做的是保存对原始String的后备数组的引用; 即包含字符的数组。

但话说samplel ,为samplel分配null并不足以使整个原始字符串的状态无法访问。 原始String的整个后备arrays将保持可访问状态……这意味着它不会成为垃圾收集的候选者。

但还有另一个复杂因素。 您将sample1设置为String文字,并且始终可以访问表示String文字的String对象(除非整个类被卸载!)

但是通过将samplel明确定义为null,sample1和sample2是否可用于垃圾收集?

原始sample1对象将保持完全可访问状态,并且sample2将保持可访问状态,除非该变量超出范围。

如果sample1不是文字,并且没有其他参考文献,那么答案就会有所不同。 sample1对象将无法访问,但其后备数组仍可通过sample2访问。


在第二个示例中,复制子字符串会导致创建新的String。 并且保证新String不会与原始String和临时子字符串共享后备数组。 在这种情况下,分配null是不必要的。

现在,sample1和sample2都可用于垃圾收集吗?

对于sample1是文字的情况,答案与上述相同。

如果sample1不是文字,并且没有其他引用,则sample1和临时子字符串现在将无法访问。


我只是想知道String构造函数在哪里有用。

理论上它将是。

在实践中,它取决于当GC最终到处查看时是否仍然可以访问引用…还有关于所讨论的字符串是否足够大且数量足以对内存使用产生重大影响。

并且在实践中, 通常不满足该前提条件并且创建一个通常没有帮助的新字符串。

请记住,在Java中, String是不可变的。 在这种情况下, sample1将被丢弃,但sample2从未指向sample1 :它指向JVM中单独保存的不可变字符串,该字符串最迟在调用substring时创建。

当您将sample1设置为null时,它指向的内存可用于垃圾回收(假设没有其他字符串保持相同的值,并且没有其他变量指向该位置)。 当您使用new关键字(或通过赋值原语隐式地执行此操作)时,会在堆上分配新内存(通常;字符串是不可变的并且共享相同的内存)。 如果没有指针(读取:任何命名变量)指向给定的内存位置,则它可用于垃圾收集。

请记住:在没有对象引用的任何情况下,它都可用于垃圾回收。 对象不是由分配给它们的变量名定义的,而是内存中的位置,变量名称充当这些对象的指针(引用)。 字符串有些不同,因为它们是不可变的,并且JVM可能选择不进行垃圾收集,原因与引用无关。