【问题标题】:Will this cause memory leak in java?这会导致java中的内存泄漏吗?
【发布时间】:2012-11-28 03:39:30
【问题描述】:

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

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机制。它将如何处理这种情况?它会在运行时立即删除这两个实例,还是只是对内存空间进行签名并让它们不理会?如果我有 100 万个这样的实例形成一个循环并且没有外部引用怎么办?清理会不会让 GC 线程挂起?

【问题讨论】:

  • 简短回答:不,不会。([标准] JVM 不是引用计数;它检查对象可达性 只有这样循环才不会导致问题。)
  • 标准的 Java mark and sweep GC 不会有这些问题。
  • 查看这个相关问题 - stackoverflow.com/questions/4891133/…
  • 嗯,第二个问题实际上是在问:一次性删除 100 万个实例的过程是否会出现性能相关问题?

标签: java garbage-collection


【解决方案1】:

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

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

【讨论】:

    【解决方案2】:

    循环引用可能会导致某些垃圾收集策略(例如reference counting)的幼稚实现发生内存泄漏。 (这并不是说引用计数是幼稚的,而是说糟糕的实现可能会遇到这个问题。)

    但是,这个问题对于实施 GC 的人来说是众所周知的,并且可以避免。此外,大多数现代 JVM 使用分代垃圾收集器,它们通常不会遇到此类问题。

    【讨论】:

    • 实际上,世代收藏家确实在一定程度上受到了这个问题的困扰。但它被认为是一种性能权衡。不过,非分代的标记和清除收集器在循环方面没有问题。
    • Nit:引用计数实现,如 Python,can handle this case as well。他们可以使用“循环检测”来处理此类情况。
    【解决方案3】:

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

    【讨论】:

    • a1 在 a1 引用为空时不符合垃圾回收条件,因为在 a2 中仍然存在对它的引用,并且 a2 仍然附加到线程。一旦 a2 为空,对象继续相互引用,但由于没有线程可以访问它们,它们有资格进行垃圾回收。所以你的“当你做 a1 = null a1 有资格获得 GCed”的陈述是不正确的。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多