我想这样的程序......
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的引用。
答案 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 进行垃圾收集并立即完成。
但是,要显示的消息必须发生三个事件:
无法保证所有这些事件都会在应用程序退出之前发生,而是在创建实例和打印“完成”之间的窗口中单独发生。
最重要的是,您永远不应该依赖Java应用程序中的最终化。