这会导致java内存泄漏吗?

这会导致java内存泄漏吗?,java,garbage-collection,Java,Garbage Collection,这是一个面试问题,但我不太确定答案是否正确。假设我们有一些类,如: public class A { public Object link; public A() { link = null; } } 然后我们创建两个实例: A a1 = new A(); A a2 = new A(); a1.link = a2; a2.link = a1; 然后我们发布参考: a1 = null; a2 = null; 然后问题是:因为JVM将使用GC机制。它将如

这是一个面试问题,但我不太确定答案是否正确。假设我们有一些类,如:

public class A {
    public Object link;
    public A() {
        link = null;
    }
}
然后我们创建两个实例:

A a1 = new A();
A a2 = new A();
a1.link = a2;
a2.link = a1;
然后我们发布参考:

a1 = null;
a2 = null;

然后问题是:因为JVM将使用GC机制。它将如何处理这个案件?它会在运行时立即删除这两个实例,还是只对内存空间进行签名,而不处理它们?如果我有一百万个这样的实例,它们形成一个循环,并且没有外部引用,会怎么样?清理是否会使GC线程挂起?

周期性引用可能会导致某些垃圾收集策略(例如)的幼稚实现出现内存泄漏。(这并不是说引用计数是幼稚的,而是说糟糕的实现可能会受到这个问题的影响。)


然而,实施地面军事系统的人都知道这个问题,并且可以避免。此外,大多数现代JVM都使用分代垃圾收集器,这些垃圾收集器通常不会遇到此类问题。

对象本身可以通过任意数量的链接(如您所述的一百万个循环)相互引用。如果没有返回到线程的“路由”,则无论对象连接到多少其他符合垃圾收集条件的节点,对象都符合垃圾收集条件


现在,这并不意味着他们将被收集,只是他们有资格。所以,如果您的垃圾收集器决定不处理它们,那么我认为这可能被视为内存泄漏。您不能保证它们会消失。

根据代码a1的当前逻辑,a2有一个指向a2的成员变量,a2有一个指向a1的ha成员变量。当您执行a1=null时,a1有资格获得GCD。a2的情况也是如此。现在,当GC运行时,它会尝试查看哪些对象从根开始是可访问的,即使这两个对象相互引用,它们在从根开始的链中也是不可访问的(隔离的情况),因此它们会毫无问题地被垃圾收集。

简短回答:不,不会。(标准的JVM不是引用计数;它只检查对象的可访问性,这样循环就不会引起问题。)标准的Java标记和扫描GC在这些方面不会有问题。请参阅这个相关的问题,第二个问题实际上是在问:一次删除100万个实例的过程是否会产生与性能相关的问题?事实上,世代收集器确实在一定程度上受到了这个问题的影响。但这被认为是一种性能权衡。不过,非代标记和扫描收集器在循环方面没有问题。Nit:引用计数实现,如Python。他们可以使用“循环检测”来处理这种情况。当a1引用为空时,a1不符合垃圾收集的条件,因为a2中仍然有对它的引用,并且a2仍然连接到线程。a2为空后,对象将继续相互引用,但由于没有线程可以访问它们,因此它们有资格进行垃圾收集。所以你说“当你做a1=null时,a1有资格获得GCD”是不正确的。