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

时间:2011-04-16 23:18:20

标签: java garbage-collection

让我们假设,有一个Tree对象,有一个根TreeNode对象,每个TreeNode都有leftNode和rightNode对象(例如BinaryTree对象)

如果我打电话:

myTree = null;

树中相关的TreeNode对象真的发生了什么?将垃圾收集,或者我必须设置树对象内的所有相关对象?

6 个答案:

答案 0 :(得分:32)

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

  

“可访问的对象是任何可以从任何活动线程继续计算中访问的对象。”

只要对象可以访问 * ,就不符合垃圾回收的条件。

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

在实践中,(保守的)可达性是通过追踪来计算的;通过以下从类(静态)变量开始的引用和线程堆栈上的局部变量来查看可以达到的内容。


以下是您的问题的含义:

  

如果我调用:myTree = null;树内相关的TreeNode对象会发生什么?也会被垃圾收集,或者我必须在树对象中设置null所有相关对象??

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

  1. 没有立即发生
  2. 如果以前只能通过根节点访问内部节点 ,那么它们现在无法访问,并且有资格进行垃圾回收。 (在这种情况下,不需要为内部节点分配null。)
  3. 但是,如果内部节点可通过其他路径访问,则可能仍然可以访问,因此不符合垃圾回收的条件。 (在这种情况下,将null分配给对内部节点的引用是错误的。您正在拆除其他人可能稍后尝试使用的数据结构。)
  4. 如果myTree 包含最后剩余可访问树根的引用,则归零内部引用是错误的,原因与在3.上面。


    那么应该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的堆栈示例就是一个例子。

    4. 应该注意的是,编译器/运行时有时会发现范围内的变量实际上已经死了。例如:

      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的用例无关。

答案 1 :(得分:5)

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

要让垃圾收集器删除对象myTree,只需在将gc()设置为null后调用myTree=null; System.gc();

{{1}}

请注意,只有在没有其他引用指向它时才会删除该对象。

答案 2 :(得分:4)

除非您有其他参考(可能是手动),否则它们将被垃圾收集。如果您只是引用了树,那么是的,它们将被垃圾收集。

答案 3 :(得分:4)

您不能将对象设置为null,只能设置一个可能包含指向此对象的指针/引用的变量。对象本身不受此影响。但是,如果现在没有从任何生命线程(即任何正在运行的方法的局部变量)到您的对象的路径存在,那么如果需要内存,它将被垃圾收集。这适用于任何对象,也适用于原始树对象引用的对象。

请注意,对于局部变量,如果方法(或块)无论如何都会很快完成,通常不必将它们设置为null

答案 4 :(得分:1)

在Java中,您不需要将对象显式设置为null以允许它们进行GC。当没有对它的引用时,对象符合GC的条件(忽略java.lang.ref.*类)。

答案 5 :(得分:0)

当没有对象的引用时,会收集对象。

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

如果您对树之外的节点有出色的引用,那么当然不是这种情况。一旦这些引用超出范围(以及只有它们引用的任何内容),这些将得到GC。