首先要说的是垃圾收集不会立即发生。因此,分配null
给任何东西都不会/不会导致垃圾收集。可能会导致对象变得无法访问......这将使其成为未来 GC 运行中垃圾收集的潜在候选对象。
现在到你的具体例子。
重要提示:以下仅适用于较旧的 JVM;即 Java 7 更新 5 及更早版本。在 Java 7 更新 6 中,它们进行了更改String.substring()
,以便目标字符串和生成的子字符串不共享支持数组。这消除了substring
.
该substring
方法不会在新字符串中引用原始字符串。它实际上所做的是保存对原始字符串支持数组的引用;即保存字符的数组。
但是话虽如此,分配null
给samplel
并不足以使整个原始字符串的状态不可达。原始字符串的整个后备数组将保持可访问性......这意味着它不会成为垃圾收集的候选者。
但还有另一个并发症。您设置sample1
为 String 文字,并且表示 String 文字的 String 对象始终是可访问的(除非整个类被卸载!)
但是通过将 samplel 显式定义为 null,sample1 和 sample2 是否可用于垃圾回收?
原始sample1
对象将保持完全可访问,并且sample2
除非该变量超出范围,否则将保持可访问。
如果sample1
不是文字并且没有其他参考,那么答案会有所不同。该sample1
对象将无法访问,但其支持数组仍可通过sample2
.
在您的第二个示例中,复制子字符串会导致创建一个新字符串。并且保证新字符串不会与原始字符串和临时子字符串共享后备数组。在这种情况下,分配null
是不必要的。
现在 sample1 和 sample2 都可用于垃圾收集吗?
sample1
对于字面量的情况,答案与上述相同。
如果sample1
不是文字并且没有其他对它的引用,那么sample1
临时子字符串现在将无法访问。
我只想知道 String 构造函数在哪里有帮助。
理论上会的。
在实践中,这取决于当 GC 最终开始查找时引用是否仍然可以访问......以及所讨论的字符串是否足够大并且足够多以对内存使用产生重大影响。
在实践中,通常不满足该前提条件,并且创建这样的新字符串通常无济于事。