繁体   English   中英

Java中的垃圾收集器-将对象设置为null

[英]Garbage collector in java - set an object null

假设有一个Tree对象,其中有一个root TreeNode对象,并且每个TreeNode都有leftNode和rightNode对象(例如BinaryTree对象)

如果我打电话:

myTree = null;

树内相关的TreeNode对象真正发生了什么? 也会收集垃圾,还是我必须将树对象内的所有相关对象设置为null?

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

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

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

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

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


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

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

假设myTree包含对myTree的最后剩余可访问引用。

  1. 什么都不会立即发生
  2. 如果以前只能通过根节点访问内部节点,那么现在它们是不可访问的,并且可以进行垃圾回收。 (在这种情况下,不必为对内部节点的引用分配null 。)
  3. 但是,如果内部节点可以通过其他路径访问,则它们可能仍然可以访问,因此不符合垃圾收集的条件。 (在这种情况下,将null分配给对内部节点的引用是一个错误。您正在分解一个数据结构,以后可能会尝试使用该数据结构。)

如果myTree 包含对myTree最后剩余可访问引用,则出于与上述3.相同的原因,使内部引用为myTree是错误的。


因此,什么时候应该 null可帮助垃圾收集器的内容?

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

  1. 类变量中的对象引用...(根据定义)永远不会超出范围。
  2. 仍在范围内的局部变量中的对象引用...但不会使用。 例如:

      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编译器可以解决这个问题。

  3. 实例变量或数组单元中的对象引用(其中数据结构不变表示将不使用它们)。 @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-实际上,我们在这里谈论的是强大的可达性。 当考虑软引用,弱引用和幻像引用时,GC可达性模型更加复杂。 但是,这些与OP的用例无关。

2-在Java 11中,有一个称为Epsilon GC的实验性GC ,它明确不收集任何内容。

myTree只是先前指向堆中对象的引用变量。 现在,您将其设置为null。 如果您没有对该对象的任何其他引用,则该对象将有资格进行垃圾回收。

要让垃圾收集器删除对象myTree只需将其设置为null后调用gc()即可

myTree=null;
System.gc();

请注意,仅当没有其他引用指向该对象时,该对象才被删除。

除非您有其他引用(可能是手册),否则它们将被垃圾回收。 如果您仅引用树,则可以,它们将被垃圾收集。

您不能将对象设置为null ,而只能将一个变量包含可能指向该对象的指针/引用。 对象本身不受此影响。 但是,如果现在不存在从任何活动线程(即任何正在运行的方法的局部变量)到您的对象的路径,则在需要内存时以及在需要内存时都将对其进行垃圾回收。 这适用于任何对象,也适用于从原始树对象引用的对象。

请注意,对于局部变量,如果方法(或块)将很快完成,通常不必将其设置为null

在Java中,您无需将对象显式设置为null即可对其进行GC处理。 如果没有对对象的引用(忽略java.lang.ref.*类),则对象可以使用GC。

没有更多引用可收集对象。

在您的情况下,将收集由myTree (根节点)正式引用的对象直接引用的节点,依此类推。

如果您对树外部的节点有出色的引用,那么情况当然不是这样。 一旦这些引用超出范围(连同它们所引用的所有内容),它们将被GC

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM