在java中的垃圾收集器 - 设置对象为null [英] Garbage collector in java - set an object null

查看:100
本文介绍了在java中的垃圾收集器 - 设置对象为null的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

假设有一个Tree对象,它有一个根节点TreeNode对象,并且每个TreeNode都有LeftNode和RightNode对象(例如一个BinaryTree对象)。

如果我打电话:

  myTree = null; 

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

解决方案

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


可到达对象是可以从任何潜在的继续计算中访问的任何对象


只要对象可以到达 * ,它就是没有资格进行垃圾回收。



JLS将它留给Java实现,以确定如何确定是否可以访问对象。如果实现不能确定,则将理论上无法访问的对象视为可访问对象并且不收集它。 (实际上,JLS允许实现不收集任何东西,尽管如此,没有合理的实现。)实际上,(保守)可达性是通过跟踪来计算的;看看下面的引用可以达到的效果:从类(静态)变量开始,以及线程堆栈上的局部变量。 >这是你的问题意味着什么:


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


假设 myTree 包含树根的最后一个可到达引用。
$ b


  1. Nothing 立即发生

  2. 如果内部节点以前只能通过根节点到达,那么它们现在 无法访问,并有资格进行垃圾回收。 (在这种情况下,将 null 分配给内部节点的引用是不必要的。)然而,如果内部节点可以通过其他路径,它们大概仍然可以访问,因此不符合垃圾回收的条件。 (在这种情况下,将 null 分配给内部节点的引用是一个错误,您正在拆除某个数据结构,以便以后尝试使用其他的数据结构。)
  3. $如果 myTree 不包含最后剩下的 / em>可到达引用树根,然后将内部引用归零是出于与上面3.中相同的原因。






    所以当应该 null 帮助垃圾收集器的事情时



    您需要担心的情​​况是,当您 可以发现某些单元格(本地,实例或类变量或数组元素)中的引用不会再次使用时,但编译器和运行时不能!这些案例大致分为三类:


    1. 类变量中的对象引用......哪些(根据定义)永远不会超出范围。 / li>
    2. 局部变量中的对象引用仍然在作用域中,但不会被使用。例如:

        public List< Pig> pigSquadron(boolean pigsMightFly){
      List< Pig> airbornePigs = new ArrayList< Pig>();
      while(...){
      Pig piggy = new Pig();
      ...
      if(pigsMightFly){
      airbornePigs.add(piggy);
      }
      ...
      }
      返回airbornePigs.size()> 0? airbornePigs:null;

      $ / code>

      在上面,我们知道如果 pigsMightFly 为false,列表对象将不会被使用。但是没有一个主流的Java编译器可以预料到这一点。


    3. 实例变量或数组单元格中的数据结构不变的对象引用意味着它们赢得不要使用。 @ edalorzo的堆栈示例就是一个例子。


    值得注意的是,编译器/范围内变量实际上已经死亡。例如:

      public void method(...){
    Object o = ...
    对象p = ...
    while(...){
    //将事物处理为'o'和'p'
    }
    //不再引用'o '
    //做很多事情'p'
    }

    一些Java编译器/运行时可能会检测到循环结束后不需要'o',并将变量视为已死。






    *实际上,我们在这里讨论的是 strong 可达性。当您考虑软,弱和幻影参考时,GC可达性模型更为复杂。但是,这些与OP的用例无关。


    Lets assume, there is a Tree object, with a root TreeNode object, and each TreeNode has leftNode and rightNode objects (e.g a BinaryTree object)

    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??

    解决方案

    Garbage collection in Java is performed on the basis of "reachability". The JLS defines the term as follows:

    "A reachable object is any object that can be accessed in any potential continuing computation from any live thread."

    So long as an object is reachable*, it is not eligible for garbage collection.

    The JLS leaves it up to the Java implementation to figure out how to determine whether an object could be accessible. If the implementation cannot be sure, it is free to treat a theoretically unreachable object as reachable ... and not collect it. (Indeed, the JLS allows an implementation to not collect anything, ever! No reasonable implementation would do that though.)

    In practice, (conservative) reachability is calculated by tracing; looking at what can be reached by following references starting with the class (static) variables, and local variables on thread stacks.


    Here's what this means for your question:

    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??

    Let's assume that myTree contains the last remaining reachable reference to the tree root.

    1. Nothing happens immediately.
    2. If the internal nodes were previously only reachable via the root node, then they are now unreachable, and eligible for garbage collection. (In this case, assigning null to references to internal nodes is unnecessary.)
    3. However, if the internal nodes were reachable via other paths, they are presumably still reachable, and therefore NOT eligible for garbage collection. (In this case, assigning null to references to internal nodes is a mistake. You are dismantling a data structure that something else might later try to use.)

    If myTree does not contain the last remaining reachable reference to the tree root, then nulling the internal reference is a mistake for the same reason as in 3. above.


    So when should you null things to help the garbage collector?

    The cases where you need to worry are when you can figure out that that the reference in some cell (local, instance or class variable, or array element) won't be used again, but the compiler and runtime can't! The cases fall into roughly three categories:

    1. Object references in class variables ... which (by definition) never go out of scope.
    2. Object references in local variables that are still in scope ... but won't be used. For example:

       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;
       }
      

      In the above, we know that if pigsMightFly is false, that the list object won't be used. But no mainstream Java compiler could be expected to figure this out.

    3. Object references in instance variables or in array cells where the data structure invariants mean that they won't be used. @edalorzo's stack example is an example of this.

    It should be noted that the compiler / runtime can sometimes figure out that an in-scope variable is effectively dead. For example:

    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'
    }
    

    Some Java compilers / runtimes may be able to detect that 'o' is not needed after the loop ends, and treat the variable as dead.


    * In fact, what we are talking about here is strong reachability. The GC reachability model is more complicated when you consider soft, weak and phantom references. However, these are not relevant to the OP's use-case.

    这篇关于在java中的垃圾收集器 - 设置对象为null的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆