Java SCJP模拟问题:有多少对象符合垃圾收集的条件?

Java SCJP模拟问题:有多少对象符合垃圾收集的条件?,java,garbage-collection,scjp,Java,Garbage Collection,Scjp,(在这个网站上)有人问我一个问题:在代码示例的第//some code-go-here行中,有多少对象符合垃圾收集的条件 class A { private B b; public A() { this.b = new B(this); } } class B { private A a; public B(A a) { this.a = a; } } public class Test { publi

(在这个网站上)有人问我一个问题:在代码示例的第//some code-go-here行中,有多少对象符合垃圾收集的条件

class A {
    private B b;
    public A() {
        this.b = new B(this);
    }
}

class B {
    private A a;
    public B(A a) {
        this.a = a;
    }
}

public class Test { 
    public static void main(String args[]) {
        A aa = new A();
        aa = null;
        // some code goes here
    }
}
正确答案是:“a和b引用的对象符合垃圾收集的条件。”。但是为什么呢?它们包含彼此的循环引用,彼此可以访问

谢谢大家!

这是因为java有一个分代垃圾收集器,所以它可以收集在它们之间有引用的对象组,但不能从主应用程序收集

还有更深入的解释

据我记忆所及(我可能错了),旧版本的java(如Java1.2)并非如此,在旧版本中,循环依赖项必须手动清除,以便GC收集它们

它们包含彼此的循环引用,彼此可以访问

是的,但是它们不再可以从其他任何地方访问,因此它们不再可以在程序中看到和使用

早期的地面军事系统在收集此类自参考对象组时遇到问题,但对于现代世代的收集器来说,这是一个已解决的问题

简而言之,GC可以遍历来自已知静态和堆栈对象的引用网络,并且

  • 将找到的所有对象复制到新内存池,自动留下任何“死”对象(这是“年轻一代”策略),或
  • 标记所有找到的对象,这样一旦遍历整个引用网络,它就可以删除所有未标记的对象(这是“旧/终身生成”策略)

    • 如果无法从任何线程访问该“岛”(或组)中的任何对象,则GC可以删除所谓的“对象岛”

      在您的示例中,您创建了一个对象A,该对象A链接到另一个对象B。但除A之外,任何人都无法“引用”对象B。您可以将这两个对象视为一个孤岛。
      当A不存在时,GC将足够聪明地发现B不能被任何其他线程引用,因此您将有2个对象被删除。

      让我们绘制场景以清楚地理解

      A a = new A() 
      
      a--------指向对象------------>a()“第一个对象”

      在A()的构造函数中,实例化B()的一个实例“第二个对象”

      在类B中,实例只是指向上面的A(),因此没有创建新对象。
      在为“a”变量指定空值时,没有引用指向()对象。现在您有2个符合GC条件的对象。不要担心类相互引用,只关注主方法内部的声明。

      我不认为gc是分代的这一事实是这里的问题;这只是某些JVM的实现细节。事实上,根集中没有引用,因此对象符合gc条件。@Simon:只有在引用计数为0时,旧gc才会对对象进行垃圾收集。因此,如果有两个对象相互引用,它们将永远不会被GCD。幸运的是,这是当今古老的历史。周期的检测与所使用的GC类型无关,唯一的例外是refcounting(仅此一项;有几种流行的语言实现使用refcounting,但有一个简单的周期GC),如果它正是因为这一限制而计数为GC,则是有争议的。因此,除非早期的Java没有正确地进行垃圾收集,否则您的内存是错误的。@Delnan我将把阅读Java 1.1/1.2文档的练习留给您:)好的,是“版权所有1998、1999、2000”,并说引用计数通常被用来解释一种垃圾收集,但它似乎不在任何JVM实现中使用。“我会看看如果我能找到其他的东西,但我认为它是不可预知的,并且会感谢引用。+ 1的定义:Sejp6的SeRea&贝茨书中的一个。