【发布时间】:2014-08-14 03:12:05
【问题描述】:
我一直在研究我的代码中的一个错误,该错误似乎是由一些“丑陋”的终结器代码引起的。代码大致是这样的
public class A {
public B b = new B();
@Override public void finalize() {
b.close();
}
}
public class B {
public void close() { /* do clean up our resources. */ }
public void doSomething() { /* do something that requires us not to be closed */ }
}
void main() {
A a = new A();
B b = a.b;
for(/*lots of time*/) {
b.doSomething();
}
}
我认为正在发生的事情是a 在main() 的第二行之后被检测为没有引用,并被终结器线程进行GC 和终结——而for 循环仍在发生,使用b 而a 仍然“在范围内”。
这合理吗? java是否允许在对象超出范围之前对其进行GC?
注意:我知道在终结器中做任何事情都是不好的。这是我继承并打算修复的代码 - 问题是我是否正确理解了根本问题。如果这是不可能的,那么更微妙的东西一定是我的错误的根源。
【问题讨论】:
-
据我所知,如果垃圾收集器 GC 对范围内的对象进行 GC,那么它就有一个 严重 错误,因为它正在收集不是垃圾的对象。所以我猜它是别的东西,但我对这些东西知之甚少,所以我完全有可能遗漏了什么......
-
您已将这些类命名为 Outer 和 Inner。 Inner 真的是 Outer 的 Inner 类吗?还是您只是表示 Outer 引用了 Inner (代码示例似乎显示了这一点)?这是一个重要的区别,因为如果是非静态内部类,则 Inner 将隐式引用 Outer。
-
一点术语说明:scope 是该语言的词汇结构。它与对象的生命周期相关,但最终不同。生命周期由 reachability 控制:如果没有代码路径可以到达对象,则它有资格被收集。通常,由当前范围内的变量引用的对象被认为是可访问的,但并非必须如此。
-
顺便说一句:在 Java 9 中,有一个明确的方法可以让对象在 sope 结束之前保持可访问性:download.java.net/java/jdk9/docs/api/java/lang/ref/…
Reference.reachabilityFende(Object) -
@awksp 不,语言/编译器的词法范围与实际可达性无关。一个对象可能不再被使用,即使它在范围内并因此被收集,另一方面,通常对象比范围更容易到达(通过停留在堆栈槽中)。但后者是一个不应该依赖的实现细节(内联和 EA 会改变代码的可达性效果)。