java中的垃圾收集器-将对象设置为null
假设有一个树对象,有一个根TreeNode对象,每个TreeNode都有leftNode和rightNode对象(例如BinaryTree对象) 如果我打电话:java中的垃圾收集器-将对象设置为null,java,garbage-collection,Java,Garbage Collection,假设有一个树对象,有一个根TreeNode对象,每个TreeNode都有leftNode和rightNode对象(例如BinaryTree对象) 如果我打电话: myTree = null; 树中的相关TreeNode对象到底发生了什么?也将被垃圾收集,或者我必须将树对象内的所有相关对象设置为null 除非您有其他参考(可能是手册),否则它们将被垃圾收集。如果您只是对树有一个引用,那么是的,它们将被垃圾收集。当不再有对对象的引用时,对象将被收集 在您的情况下,将收集由myTree(根节点)正式
myTree = null;
树中的相关TreeNode对象到底发生了什么?也将被垃圾收集,或者我必须将树对象内的所有相关对象设置为null 除非您有其他参考(可能是手册),否则它们将被垃圾收集。如果您只是对树有一个引用,那么是的,它们将被垃圾收集。当不再有对对象的引用时,对象将被收集 在您的情况下,将收集由
myTree
(根节点)正式引用的对象直接引用的节点,依此类推
当然,如果对树之外的节点有未完成的引用,则情况并非如此。一旦这些引用超出范围(以及它们只引用的任何对象),它们将得到GC。在Java中,您不需要显式地将对象设置为
null
,以允许对它们进行GC。如果没有对对象的引用(忽略java.lang.ref.*
类),则对象符合GC的条件。不能将对象设置为null
,只能设置可能包含指向此对象的指针/引用的变量。对象本身不受此影响。但是,如果现在没有从任何活动线程(即任何运行方法的局部变量)到对象的路径存在,那么在需要内存时,它将被垃圾收集。这适用于任何对象,也适用于从原始树对象引用的对象
请注意,对于局部变量,如果方法(或块)很快就会完成,通常不必将它们设置为
null
。Java中的垃圾收集是基于“可达性”执行的。JLS对术语的定义如下:
“可访问对象是可以从任何活动线程在任何可能的连续计算中访问的任何对象。”
只要对象是可访问的1,它就不符合垃圾收集的条件
JLS让Java实现决定如何确定对象是否可以访问。如果实现无法确定,可以自由地将理论上无法访问的对象视为可访问的对象。。。而不是收集它。(事实上,JLS允许实现永远不收集任何东西!任何实际实现都不会这样做。)
在实践中,(保守的)可达性是通过跟踪来计算的;从类(静态)变量和线程堆栈上的局部变量开始,看看下面的引用可以实现什么
这对你的问题意味着什么: 如果我调用:
myTree=null代码>树中的相关TreeNode对象到底发生了什么?也将被垃圾收集,或者我必须将树对象内的所有相关对象设置为null
让我们假设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;
}
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-事实上,我们在这里讨论的是可达性。当考虑软、弱和幻像参考时,GC可达性模型更为复杂。然而,这些与OP的用例无关
2-在Java 11中,有一个名为的实验GC,它显式地不收集任何东西。myTree
只是一个引用变量,它以前指向堆中的对象。现在将其设置为null。如果您没有对该对象的任何其他引用,那么该对象将有资格进行垃圾收集
要让垃圾收集器删除对象myTree
,只需在将其设置为null
后调用gc()
myTree=null;
System.gc();
请注意,只有当没有其他引用指向该对象时,才会删除该对象。我担心这句话可能会误导您,尽管它是正确的。数组中的对象可能永远不会被垃圾收集,除非您将其所在的数组索引设置为null,前提是您仍在使用数组中的其他对象。这是基于数组的堆栈中的一个经典内存泄漏。当一个对象没有更多的引用时,它有资格成为GCd。准确地说,是的,这是正确的。然而,同样迂腐的是,我可以肯定地说,如果有一个对象的引用,它就不会被GC’d。@BrianRoach