假设有一个 Tree 对象,有一个根 TreeNode 对象,每个 TreeNode 都有 leftNode 和 rightNode 对象(例如 BinaryTree 对象)
如果我打电话:
myTree = null;
在树中相关的 TreeNode 对象到底发生了什么?也将被垃圾收集,或者我必须将树对象内的所有相关对象设置为空?
最佳答案
Java 中的垃圾收集是在“可达性”的基础上进行的。 JLS 对该术语的定义如下:
"A reachable object is any object that can be accessed in any potential continuing computation from any live thread."
只要一个对象是可访问的1,它就没有资格进行垃圾回收。
JLS 将其留给 Java 实现来确定如何确定一个对象 是否可以 可访问。如果实现无法确定,则可以自由地将理论上无法访问的对象视为可访问的……而不是收集它。 (事实上,JLS 允许实现永远不收集任何东西!尽管没有实际的实现会这样做2。)
在实践中,(保守的)可达性是通过追踪来计算的;查看从类(静态)变量和线程堆栈上的局部变量开始的引用可以达到什么。
这对您的问题意味着什么:
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.。
那么应该你什么时候null
东西来帮助垃圾收集器?
您需要担心的情况是,当 您 可以确定某个单元格(本地、实例或类变量或数组元素)中的引用将不会被再次使用,但是编译器和运行时不能!这些案例大致分为三类:
- 类变量中的对象引用...(根据定义)永远不会超出范围。
仍在作用域内的局部变量中的对象引用......但不会被使用。例如:
public List<Pig> pigSquadron(boolean pigsMightFly) { List<Pig> airbornePigs = new ArrayList<Pig>(); 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',并将变量视为死变量。
1 - 事实上,我们在这里谈论的是strong可达性。当您考虑软引用、弱引用和幻像引用时,GC 可达性模型会更加复杂。但是,这些与 OP 的用例无关。
2 - 在 Java 11 中有一个名为 Epsilon GC 的实验性 GC。明确不收集任何东西。
关于java - java中的垃圾收集器-将对象设置为null,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/5690309/