【问题标题】:Object destruction when child object references a parent object [duplicate]子对象引用父对象时的对象销毁[重复]
【发布时间】:2014-11-24 15:04:12
【问题描述】:

代码示例:

public class Parent{
  public void someMethod(){
    //start of some sort of loop
    Child child = new Child(this);

    //do something
    //replaces reference from old child to new child
    child = new Child(this);
    //repeats loop
  }
}

public class Child{
   Parent parent;
   public Child(Parent parent){
     this.parent = parent;
   }
}

根据我对对象生命周期的理解,如果一个对象不再被引用,那么它将符合 gc 条件,例如当子引用更改为引用新的第二个子对象时。

但是,如果每个 Child 对象都具有对创建它的对象的引用,就像上面一样,一旦它不再被其父对象引用,它是否有资格在这种情况下进行 gc?

如果没有,我该如何写它呢?

【问题讨论】:

    标签: java object garbage-collection


    【解决方案1】:

    根据this answer

    如果无法通过 Java 的 GC 访问对象,则将其视为“垃圾” 从垃圾收集根开始的链,因此这些对象将 被收集。即使对象可能相互指向以形成一个 循环,如果从根上切下来,它们仍然是垃圾。

    所以你不需要为这个循环参考案例做任何特别的事情。

    【讨论】:

      【解决方案2】:

      如果 A 类的一个实例引用了 B 类的一个实例,而 B 类的一个实例又引用了 A 类的同一个实例,只要这些引用存在,那么两者都没有资格进行 GC。

      顺便说一句,在您的示例中,子实例被分配给父类中的本地方法变量,因此一旦该方法完成,子实例将有资格进行 GC,无论它是否包含对创建它的父实例。

      现在,如果您将 Child 实例引用存储在 Parent 类的成员中,您将拥有一个循环引用。然后,如果创建 Parent 实例的代码丢失了对 Parent 实例的所有引用,则循环引用将永远无法删除,因此这两个对象都没有资格进行 GC。

      考虑这个例子:

      public class Parent{
          private Child child;
          public Parent {
              child = new Child(this);
          }
      
          public static void main (String[] args)
          {
              while (true) {
                  parent = new Parent();
              }
          }
      }
      
      public class Child{
          Parent parent;
          public Child(Parent parent){
              this.parent = parent;
          }
      }
      

      这里,main 方法的无限循环会在每次迭代中创建一个新的 Parent 和 Child 实例,它永远不会符合 GC 条件,因此最终会耗尽内存。

      【讨论】:

      • 哦,是的,我用那个新的 Parent() 打错了,我编辑了。但是我将如何从子类中删除对 Parent 实例的引用?我应该创建一个 removeParent 方法并在其中放置对 null 的父引用吗?
      • 在上面的例子中,Parent 没有引用 Child;一个子变量是 someMethod() 方法中的一个局部变量。
      • @Nonexistent 如果您有对 Child 实例的引用,并且在 Child 类中有一个方法可以使 Parent 引用无效,则可以清除该引用。但是如果你没有对 Child 实例的引用,你就不能这样做。
      • "如果 A 类的实例引用了 B 类的实例,而 B 类的实例引用了 A 类的同一个实例,那么两者都没有资格进行 GC因为这些参考存在。”那不是真的。有关更多信息,请参阅我的答案。
      • @spaceknarf 我明白了。我错了,如果可以的话,我会删除答案。但是您从另一个问题中复制答案也是错误的。正确的做法是将此问题标记为重复。
      【解决方案3】:

      在您的someMethod() 中,您正在创建Child 类的两个实例;它们都引用同一个Parent这一事实与您创建的第一个实例将(最终)在被取消引用后(当您重新分配child变量时)被GC'd这一事实无关。并创建一个Child 对象的新实例)。

      在实践中,这并不是那么直接 - GC 过程会经历几个阶段(您可能想了解 Tenured、Eden 和 Survivor 阶段)。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2015-12-11
        • 2019-03-03
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多