【问题标题】:How many objects will be eligible for garbage collection after executing "m1=null; m2=null;"?执行“m1=null; m2=null;”后有多少对象符合垃圾回收条件?
【发布时间】:2016-01-20 09:50:06
【问题描述】:

在执行m1 = null;m2 = null;后我很困惑。有多少对象符合垃圾回收条件?

public class MyTest {
    MyTest m;

    void show() {
        System.out.println("Hello this is show method.");
    }

    public static void main(String args[]) {
        MyTest m1 = new MyTest();
        MyTest m2 = new MyTest();
        MyTest m3 = new MyTest();
        m1.m = m2;
        m2.m = m3;
        m3.m = m1;
        m1 = null;
        m2 = null;
        // Question here: How many objects will be eligible for garbage collection?
    }
}

【问题讨论】:

  • m3 到垃圾收集器“这不是你要找的两个实例!”
  • @rakeb.mazharul:有趣吗?问题的可达性方面非常简单,在“三个房子由单向街道连接成一个循环。我可以从房子 A 开车到哪些?”的水平上。如果您要推理任何重要的垃圾收集程序的内存行为,那么这种事情需要成为第二天性。由于优化存在一些复杂性,但接受的答案甚至没有提到这一点,我怀疑大多数选民都注意到了。
  • 每个答案都说“三”或“零”。这个问题无法回答,因为我们不知道 args 数组中有多少对象。人们认为数组及其元素不是对象吗?
  • @EricLippert 但是元素 m1、m2 或 m3 都不在 args 数组中。并且 args 数组中的所有元素都是可访问的,所以我看不到 args 数组如何影响可用于 GC 的对象数量。
  • @taemyr,它们必须可以从活的根中访问。为什么args还活着? GC 可以知道它从未被使用过,因此可能已经死亡。

标签: java garbage-collection


【解决方案1】:

零。

对象引用图如下:

你可以看到引用是循环的。从mainm3 的引用使m3 对象保持活动状态。反过来,m3 使m1 保持活动状态,从而使m2 不被GC。

请注意,如果您将m3 设置为null,则所有三个对象都将同时符合GC 条件,尽管每个对象都存在循环引用。 GC 足够聪明,可以确定所有引用都来自符合 GC 条件的对象,并收集所有三个。

【讨论】:

  • 你是怎么画得这么快的? +1
  • 从技术上讲,GC 不够聪明,无法找出循环引用,但它通过标记 GC 根的可访问对象来工作,因此避免了循环引用问题...
  • @Codebender 避免问题足够聪明 ;-)
  • @Codebender 实际上它必须在某种程度上找出循环引用,因为它(可能)遍历整个对象图,并且它的算法在遇到循环时不会崩溃。
【解决方案2】:

瞧! GC 不会在这里收集任何东西!让我们看看这里到底发生了什么。当您创建了MyTestm1m2m3 三个对象时,对象的创建方式如下(假设对象引用ID 从410 开始):

m1    MyTest  (id=410)
    m    null
m2    MyTest  (id=412)
    m    null
m3    MyTest  (id=414)
    m    null

初始化时

m1.m = m2;
m2.m = m3;
m3.m = m1;

对象现在看起来像:

m1    MyTest  (id=410)
    m    MyTest  (id=412)
m2    MyTest  (id=412)
    m    MyTest  (id=414)
m3    MyTest  (id=414)
    m    MyTest  (id=410)
        m    MyTest  (id=412)
            m    MyTest  (id=414)
                m    MyTest  (id=410)
                    .
                    .
                    . (This is circular)

但是在将m1m2 重新初始化为null 后,对象看起来像:

m1    null
m2    null
m3    MyTest  (id=414)
    m    MyTest  (id=410)
        m    MyTest  (id=412)
            m    MyTest  (id=414)
                m    MyTest  (id=410)
                .
                .
                .

看,m1m2 现在是 null,但它们的引用在 m3 中仍然存在!

【讨论】:

    【解决方案3】:

    可能所有 3 个。在 // 标记之后没有引用任何变量,因此优化器此时有权将它们从框架中删除。

    【讨论】:

    • 我认为 OP 的关注点在其他地方!但无论如何你是对的! +1
    • 我想起了 Raymond Chen 的优秀文章,blogs.msdn.com/b/oldnewthing/archive/2010/08/10/10048149.aspx。但是,我不确定 Java GC 是否有类似的规则。 Java 规范可能有书面承诺不收集具有根引用的对象。
    • @Brian:在这方面,Java 与 C# 一样聪明。必须强调的是,对对象实例数据的最后一次实际访问不一定是程序顺序中的最后一次访问,因为优化器可能会生成将实际字段值保存在寄存器中的代码,即使在处理其对象时也不需要对象数据。在问题的示例中,没有任何分配具有实际效果,因此所有对象可能在创建后立即被收集,或者从一开始就永远不会被创建。另见finalize() called on strongly reachable object in Java 8
    【解决方案4】:

    无,因为它们仍然可以通过您在 m3 那里构建的循环引用访问

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2023-03-27
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多