垃圾收集详细信息:此对象是否符合GC的条件?

时间:2011-05-08 13:21:44

标签: java garbage-collection

我想这样的程序......

class Test {
    public static void main(String[] args) {
        new Test();
        System.out.println("done");
    }

    protected void finalize() {
        System.out.println("this object is known to never be referenced.");
    }
}

...可能会在"this object is known to never be referenced."之前输出"done"。 (如果我错了,请纠正我!)

此外,编译器/ JVM很容易检测到“未读本地人”。例如,在下面的程序中,Eclipse注意到“本地变量t永远不会被读取”。

然而如果下面的程序(.class版本)给JVM在"this object is known to never be referenced."之前输出"done"是不合法的吗?

class Test {
    public static void main(String[] args) {
        Test t = new Test();
        System.out.println("done");
    }

    protected void finalize() {
        System.out.println("this object is known to never be referenced.");
    }
}

垃圾收集的大多数文档都谈到了可达性。鉴于t永远不会被读取,该对象显然不是“可达”,或者是

赞赏对JLS的引用。

2 个答案:

答案 0 :(得分:5)

12.6.1 of the Java Language Specification中说:

  

12.6.1实施最终确定

     

每个物体都可以用两个来表征   属性:它可以是可达的,   终结者 - 可达,或无法到达,   它也可能是未定罪的,   最终确定或最终确定。可以到达   object是可以的任何对象   任何潜在的继续访问   从任何实时线程计算。   优化变换   程序可以设计减少   对象的数量   可达到小于那些   天真地被认为是可以达到的。

     

例如,编译器或代码   生成器可以选择设置变量   或者不再是的参数   用于null以导致存储   这样的对象是潜在的   可以早点回收。

在我看来,最后一句话恰好涵盖了你所询问的案例。变量t可以在范围结束之前隐式设置为null,从而使对象无法访问。

这在C ++中会是一场灾难,因为很多代码都依赖于范围结束时的确切破坏时间(例如锁定)。

答案 1 :(得分:2)

  

...可能输出“已知此对象永远不会被引用”。在“完成”之前。

有三种可能的行为:

  • 在“完成”之前输出消息,

  • 在“完成”之后输出消息,

  • 根本不会输出“此对象永远不会被引用”消息。

(实际上,最可能的行为是最后一个。事实上,除非你在创建Test实例和打印“完成”之间产生大量垃圾,否则它是虚拟的确定性。)

  

但是,JVM输出“此对象永远不会被引用”是违法的。在“完成”之前给出下面程序的(.class版本)?

不,这不是违法的。 Test实例不能在任何可能的连续计算中从任何活动线程访问,因此无法访问。因此,JVM将 legal 进行垃圾收集并立即完成。

但是,要显示的消息必须发生三个事件:

  • GC必须运行,
  • GC必须将对象检测为无法访问,
  • GC必须完成对象。

无法保证所有这些事件都会在应用程序退出之前发生,而是在创建实例和打印“完成”之间的窗口中单独发生。


最重要的是,您永远不应该依赖Java应用程序中的最终化。