最终字段如何不泄漏内存?

时间:2014-04-25 04:59:52

标签: java memory-leaks garbage-collection final

我已经毫无疑问地使用final关键字多年来表示在实例/类的生命周期内不应更改的字段。突然间,这发生在我身上......

所以给出了这个例子:

public class TestFinalGC{

    private TestFinalGC(){}

    private final Object obj = new Object();

     public static void main(String []args){
         TestFinalGC instance = new TestFinalGC();
         // instance Ref -> actual instance ->? obj ref-> actual obj
         System.out.println(instance.obj);
         instance = null;
         //say GC makes sweep here... what happens?
         //lets assume theres more code, obj would obviously be eligible for GC on app exit.
     }
}

obj成员如何在此处泄露? final字段是否自动WeakReferences,以便如果对父项的强引用为空,它们是否有资格进行垃圾回收?

The JLS does not seem to note anything special about final

更新

因此,我的这个问题建立在“可达性”和强/弱参考密切相关的前提之上。有this confusing oracle doc on reachability让我相信嵌套引用应始终“强烈可达”。因此,我在所有对象中都取消了嵌套对象引用,但看起来显然不应该是我收到的所有注释的情况。

那么关于“可达性”,那么,如果不再能够访问父引用,那么仅仅是嵌套对象引用不再被认为是“可达”的吗?

可能确实是这个问题的前提是不正确的,但仍有一些有趣的信息要合并到这里。

1 个答案:

答案 0 :(得分:2)

正如Makoto所建议的那样,就GC而言,变量声明中final没有什么特别之处。在您的示例代码中

private final Object obj = new Object();

将与

同时进行垃圾收集
private Object obj = new Object();

两者都是强引用,但是无效并且与其父类TestFinalGC实例一起收集垃圾。这是因为当实例是GC'd时,参考字段也会被销毁,并且引用不再存在。 obj的引用计数因此减少了一个。

但是,你应该写一些像

这样的东西
Object x = myTestFinalGC.obj; // only works if your obj is not private, of course

然后该对象将不会被垃圾收集,因为它仍然会有一个引用延迟(假设这个特定的代码行在另一个类实例中,当myTestFinalGC被垃圾收集时仍保持活动状态。

tl; dr:内存分配在硬引用计数降为零时收集垃圾(当然收集器运行)。 final并未改变这一事实。