Java中的垃圾收集是基于“可达性”执行的. JLS将术语定义如下:
“A reachable object is any object that can be accessed in any potential continuing computation from any live thread.”
只要对象可以访问*,就不符合垃圾回收的条件.
JLS将其留给Java实现来确定如何确定对象是否可访问.如果实现不能确定,可以将理论上无法访问的对象视为可达…而不是收集它. (事实上??,JLS允许实现不会收集任何东西!尽管如此,没有合理的实现会这样做.)
在实践中,(保守的)可达性通过追踪来计算;通过以下从类(静态)变量开始的引用和线程堆栈上的局部变量来查看可以达到的内容.
以下是这对您的问题意味着什么:
If i call: myTree = null; what really happens with the related TreeNode objects inside the tree? Will be garbage collected as well, or i have to set null all the related objects inside the tree object??
假设myTree包含对树根的最后剩余可到达引用.
>没有立即发生.
>如果以前只能通过根节点访问内部节点,则它们现在无法访问,并且有资格进行垃圾回收. (在这种情况下,为内部节点的引用分配null是不必要的.)
>但是,如果内部节点可通过其他路径到达,则可能仍然可以访问它们,因此不符合垃圾回收的条件. (在这种情况下,为内部节点的引用分配null是一个错误.您正在拆除其他人可能稍后尝试使用的数据结构.)
如果myTree不包含对树根的最后剩余可到达引用,则归零内部引用是错误的,原因与上面的3.相同.
那么什么时候应该为了垃圾收集器而无效?
您需要担心的情??况是,您可以确定某个单元格(本地,实例或类变量或数组元素)中的引用不会再次使用,但编译器和运行时不能!案件大致分为三类:
>类变量中的对象引用……(根据定义)永远不会超出范围.
>仍在范围内的局部变量中的对象引用…但不会被使用.例如:
public List pigSquadron(boolean pigsMightFly) {
List airbornePigs = new ArrayList();
while (...) {
Pig piggy = new Pig();
...
if (pigsMightFly) {
airbornePigs.add(piggy);
}
...
}
return airbornePigs.size() > 0 ? airbornePigs : null;
}
在上面,我们知道如果pigsMightFly为false,则不会使用list对象.但是,预计没有主流的Java编译器可以解决这个问题.
>实例变量或数组单元格中的对象引用,其中数据结构不变量意味着它们不会被使用. @ edalorzo的堆栈示例就是一个例子.
应该注意的是,编译器/运行时有时会发现范围内的变量实际上已经死了.例如:
public void method(...) {
Object o = ...
Object p = ...
while (...) {
// Do things to 'o' and 'p'
}
// No further references to 'o'
// Do lots more things to 'p'
}
一些Java编译器/运行时可能能够检测到循环结束后不需要’o’,并将变量视为死.
*事实上,我们在这里谈论的是强大的可达性.当您考虑软,弱和幻像参考时,GC可达性模型会更复杂.但是,这些与OP的用例无关.