java垃圾收集和null引用
在我为OCJP学习时,我遇到了以下问题:
class CardBoard { Short story = 200; CardBoard go(CardBoard cb) { cb = null; return cb; } public static void main(String[] args) { CardBoard c1 = new CardBoard(); CardBoard c2 = new CardBoard(); CardBoard c3 = c1.go(c2); c1 = null; // do Stuff }}
当达到// doStuff时,有多少对象符合GC条件?
正确的答案是2,意思是c1
及其story
对象。
当达到// doStuff行时,c3也为空。 为什么它也不符合GC的条件?
c3是一个带有空引用的本地句柄,它不指向(并且已经指向)已分配的对象。 因此对GC没有任何意义。
c3
不是一个对象。 它是一个引用null的变量。 变量不能符合GC的条件。 只有对象才有资格使用GC。
符合GC条件的对象是最初由c1
引用的Cardboard,最初由CardBoard引用的Short实例最初由c1
引用。
垃圾收集器扫描内存中的对象,当它找到一个检查指向它的句柄时(而不是反之)当调用垃圾收集器时,没有句柄指向它们的对象(内部内存)将从内存中删除。 在这个代码场合,你只有2个在内存中创建的对象但是有三个句柄。 垃圾收集器将仅删除最多2个对象(因为只存在两个对象)C3仅指向空位置。 C1,C2,C3未被移除。 它们用于指向的对象将被删除(如果没有其他句柄指向它们)。 所以此时由于C3从未指向内存中的对象,因此将其设置为null对垃圾收集器没有任何影响。
希望我有所帮助
你的CardBoard#go()
方法什么都不做。 它接收对某个对象的引用,立即忘记它,替换为null
,并返回此null
值。
所以,这条线
CardBoard c3 = c1.go(c2);
也什么都不做,即没有创建对象。 只为null分配给c3
。 所以它不是垃圾收集因为它已经不存在了。
c3本身只是一个引用变量 ,它不在堆空间中 (即不在垃圾收集的范围内)
线CardBoard c3 = c1.go(c2);
仅将c3引用设置为null因此,c3对垃圾回收没有影响,因为它不会使任何对象符合条件。
c3没有对象的引用,只是让人产生一些困惑。
我们创建了两个对象c1和c2,我们遗漏的是Short类型的包装器对象,所以基本上我们总共创建了四个对象。
当我们使c1 = null时,它意味着我们使用c1访问的短对象可用于GC,而不是我们可以使用c2访问的短对象。
这可以使用以下代码进行validation:
公共类CardBoard {
Short story = 200; CardBoard go(CardBoard cb) { cb = null; return cb; } public static void main(String[] args) { Runtime run = Runtime.getRuntime(); CardBoard c1 = new CardBoard(); CardBoard c2 = new CardBoard(); CardBoard c3 = c1.go(c2); // System.out.println(run.freeMemory()); run.gc(); // System.out.println(run.freeMemory()); c1.story = 100; System.out.println(c1.story); c1 = null; run.gc(); System.out.println(c2.story); }
}
输出:100 200
这意味着我们可以从c1访问的c1和短篇故事可用于垃圾收集而不是c2的短篇故事。