Java中的垃圾收集是基于“可达性”进行的。JLS对术语的定义如下:

“可达对象是可以从任何活动线程进行任何潜在的连续计算中访问的任何对象。”

只要对象是可到达的*,就不符合垃圾回收的条件。

JLS将其留给Java实现来弄清楚如何确定对象是否可访问。如果无法确定实现,则可以自由地将理论上无法到达的对象视为可到达的对象...而不收集它。(实际上,JLS允许实现永远不收集任何东西!但是,没有合理的实现会这样做。)

在实践中,(保守)可达性是通过跟踪来计算的;通过遵循从类(静态)变量和线程堆栈上的局部变量开始的引用,可以了解可以达到的目标。

这对您的问题意味着什么:

如果我打电话给我:myTree = null;树内相关的TreeNode对象真正发生了什么?也会收集垃圾,还是我必须将树对象内的所有相关对象设置为null?

假设其中myTree包含对树根的最后剩余的可达引用。

什么都不会立即发生。

如果以前只能通过根节点访问内部节点,那么现在它们是不可访问的,并且可以进行垃圾回收。(在这种情况下,null不必分配对内部节点的引用。)

但是,如果内部节点可以通过其他路径访问,则它们可能仍然可以访问,因此不符合垃圾收集的条件。(在这种情况下,分配null对内部节点的引用是一个错误。您正在分解一个数据结构,以后可能会尝试使用该数据结构。)

如果myTree 不包含对树根的最后一个剩余的可达引用,则出于与上述3中相同的原因,使内部引用为空是错误的。

所以,当应你null的事情来帮助垃圾收集器?

您需要担心的情况是,您可以确定不再重用某些单元格(局部,实例或类变量或数组元素)中的引用,但是编译器和运行时不能使用!案件大致分为三类:

类变量中的对象引用...(根据定义)永远不会超出范围。

仍在范围内的局部变量中的对象引用...但不会使用。例如:

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,则不会使用列表对象。但是没有主流的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的用例无关。