2013-05-16 30 views
12

我已经通过在线阅读了一些Java垃圾收集指南,但我仍然有点不清楚,希望确保在代码中没有内存泄漏。如果实例变量仍然有引用,Java GC是否销毁对象?

Java GC是否收集丢失其引用的对象,但其变量仍有参考?

所以我们可以说我有SomeObject:

public class SomeObject { 
    public ObjectVar var; 

    public SomeObject() { 
     var = new ObjectVar(); 
    } 
} 

而且我的代码:

SomeObject obj1 = new SomeObject(); 
SomeObject obj2 = new SomeObject(); 
obj2.var = obj1.var; 
obj1 = null; 

所以OBJ1的变种具有一定的参考,但OBJ1不再有任何引用。那么,GC是否会销毁obj1,但保持var还活着? (我假设如此,只是想确定)。谢谢!

+0

GC的基本规则是,如果GC对一个对象会影响你的程序,它不会发生。 (除非你使用关注GC的专门工具,但如果你使用的话,你会知道的。) –

+0

你可能想阅读[“中年危机”](http://blogs.msdn。 COM/b /瑞康/存档/ 2003/12/04/41281.aspx)。 – Mehrdad

回答

12

这里是什么事情发生(见下面的评论)

// obj1 and obj1.var get created 
SomeObject obj1 = new SomeObject(); 
// obj2 and obj2.var get created 
SomeObject obj2 = new SomeObject(); 
// old obj2.var becomes eligible for GC 
obj2.var = obj1.var; 
// obj1 becomes eligible for GC 
obj1 = null; 

最终,两个对象仍然没有得到GCD - obj2和前obj1.var这是目前被引用为obj2.var

注:在ObjectVar类是一个非静态内部类的SomeObject,保持一个参考obj1.var也将保持obj1围绕一个特例。这是因为SomeObject.ObjectVar类内部有一个类型为SomeObject的隐藏变量,它引用内部类的外部对象。

+0

好的谢谢!但现在我很困惑,因为两个人有不同的答案。如果ObjectVar是SomeObject的子类(或内部类),上面的代码将使obj1不符合GC的条件? – baekacaek

+1

@baekacaek ZyyaoWei的评论只考虑了静态的内部类,在这种情况下它并不重要。非静态内部类和匿名或命名方法局部类可以防止垃圾收集主机对象,但静态内部类不能。 – dasblinkenlight

+0

再次感谢您的澄清和快速回复! – baekacaek

3

当然可以。

请记住,您在var字段中存储的内容实际上是对象的引用,而不是对象本身。因此,当GC收集obj1,在var对象是不变(不得触碰),特别是因为它具有从obj2一个参考,这是仍然健在的..

+0

谢谢,如果ObjectVar是SomeObject的内部类,是否也适用? – baekacaek

+0

那应该不重要,因为不管obj2是什么引用该对象。 –

+2

如果它是一个静态的内部类,那确实无关紧要。但是,当它是一个非静态的内部类时,'var'对外部类有一个“反向引用”,这可能会让所有者的活动时间超过预期的时间。 – dasblinkenlight

0

是的 - 行为与您描述的一样。垃圾收集的一般规则是,只有当通过任何硬引用无法访问它们时,对象才会变为合格。任何可以达到这种方式的物体都将永远不会被垃圾收集(除软/弱参考外)。

0

简而言之,如果某个对象仍然可以通过引用路径到达,则它将保证能够继续收集。如果没有这样的路径,则不能再访问该对象,并且可以安全地收集该对象。

前两行后,内存看起来是这样的:

o1 --> SomeObj#1 --> ObjectVar#1 
o2 --> SomeObj#2 --> ObjectVar#2 

所有4个对象,可以达到,如果垃圾收集是在这个时候发生,没有人会被收集。

3号线后,它看起来像这样:

o1 --> SomeObj#1 --> ObjectVar#1 
        ^
o2 --> SomeObj#2 ----- ObjectVar#2 

现在,只有3个对象即可到达;垃圾收集器可能会删除ObjectVar#2。

4号线后,它看起来像这样:

o1  SomeObj#1 --> ObjectVar#1 
        ^
o2 --> SomeObj#2 ----- ObjectVar#2 

只有两个对象依旧可达;垃圾收集器可能会删除SomeObj#1和ObjectVar#2,但必须保留SomeObj#2和ObjectVar#1。