String samplel = "ToBeGarbageCollected";
String sample2 = samplel.substring(0, 1);
samplel = null;
我知道内部的子字符串将保留原始字符串的引用。
但是通过明确地将samplel
定义为null
,sample1和sample2是否可用于垃圾收集?
我记得在某处,如果父对象显式设置为null
,则所有子值都可用于垃圾回收。这对上述情况有利吗?
我只是好奇这是否是父母子女关系的情景?如果不是,这会导致sample1
或sample2
可用于垃圾收集吗?
String samplel = "ToBeGarbageCollected";
String sample2 = new String(samplel .substring(0, 1));
samplel = null;
答案 0 :(得分:6)
首先要说的是垃圾收集不会立即发生。因此,将null
分配给任何内容都不会/不能导致垃圾回收。 可能做的是使对象变得无法访问 ...这将使其成为未来GC运行中垃圾收集的潜在候选者。
现在举个具体的例子。
重要说明:以下仅适用于较旧的JVM;即Java 7更新5及更早版本。在Java 7更新6中,他们更改了String.substring()
,以便目标字符串和生成的子字符串不共享后备数组。这消除了substring
潜在的存储泄漏问题。
substring
方法不会在新String中引用原始String。它实际上做的是保存对原始String的后备数组的引用;即包含字符的数组。
但话说回来,将null
分配给samplel
并不足以使整个原始字符串的状态无法访问。原始String的整个后备阵列将保持可访问状态......这意味着它不会成为垃圾收集的候选者。
但还有另一个复杂因素。您将sample1
设置为String文字,并且表示字符串文字的String对象始终可以访问(除非整个类被卸载!)
但是通过将samplel显式定义为null,sample1和sample2是否可用于垃圾收集?
原始sample1
对象将保持完全可访问状态,并且sample2
将保持可访问状态,除非该变量超出范围。
如果sample1
不是文字,并且没有其他参考文献,那么答案就会有所不同。 sample1
对象无法访问,但其后备数组仍可通过sample2
访问。
在第二个示例中,复制子字符串会导致创建新的String。并且保证新String不会与原始String和临时子字符串共享后备数组。在这种情况下,分配null
是不必要的。
现在,sample1和sample2都可用于垃圾收集吗?
对于sample1
是文字的情况,答案与上述答案相同。
如果sample1
不是文字,并且没有其他引用,那么sample1
和临时子字符串现在将无法访问。
我只想知道String构造函数在哪里有用。
理论上它会是。
在实践中,它取决于GC最终是否仍然可以查看引用...以及相关的字符串是否足够大且数量足以对内存使用产生重大影响。
在实践中,前提条件通常不满足并且创建一个新的字符串,就像通常一样没有帮助。
答案 1 :(得分:2)
请记住,在Java中String
是不可变的。在这种情况下,sample1
将被丢弃,但sample2
从未指向sample1
:它指向JVM中单独持有的不可变字符串,该字符串最迟在{{1}时创建被叫了。
当您将substring
设置为null时,它指向的内存可用于垃圾收集(假设没有其他字符串保持相同的值,并且没有其他变量指向该位置)。当您使用sample1
关键字(或通过赋予基元隐式地执行此操作)时,会在堆上分配新内存(通常;字符串是不可变的并且共享相同的内存)。如果没有指针(读取:任何命名变量)指向给定的内存位置,它可用于垃圾收集。
请记住:在没有对象引用的任何情况下,它都可用于垃圾回收。对象不是由分配给它们的变量名定义的,而是内存中的位置,变量名称充当这些对象的指针(引用)。字符串有些不同,因为它们是不可变的,并且JVM可能会选择不进行垃圾收集,原因与引用无关。