我知道如果指向对象的引用变量被手动设置为null或设置为指向另一个对象,则java GC可以销毁堆上的对象:
TestObject test = new TestObject();
test.dosomething();
test = null;
我的问题是,如果我在创建它时没有给该对象一个名称(引用变量),那么在完成对象后,如何释放该对象占用的内存:
(new TestObject()).dosomething();
在程序结束之前,这个对象会永远存在于堆上吗?
答案 0 :(得分:3)
使用new
创建对象并在其上调用方法dosomething()
之后,没有任何引用,因此它有资格进行垃圾回收。
即使您创建了两个使用引用指向彼此的对象,并且它们不再具有与根引用的连接,它们也将符合gc的条件(jvm可以在没有根连接的情况下检测此循环引用)。
所以要回答你的问题:否你的第二个例子中的那个对象在你上面调用dosomething
后会被gc-ed。
请注意:在实践中,您不需要null
您的引用(我实际上几乎从不这样做)只要将它们保留在本地范围内就足够了所以当您保留局部变量时得到清理。
答案 1 :(得分:1)
我将通过字节代码解释这一点。首先要注意的是,虽然对象存在可访问的引用,但无法收集该对象。这方面的一个重要方面是,如果参考值在方法的堆栈帧中的堆栈上,则可以访问被引用的对象。因此它不能被垃圾收集。
编译以下程序
public class Example {
public static void main(String[]args) {
new Example().sayHello();
}
public void sayHello() {}
}
运行javap -c Example
将为您提供类似
public static void main(java.lang.String[]);
Code:
stack=2, locals=1, args_size=1
0: new #2 // class Example
3: dup
4: invokespecial #3 // Method "<init>":()V
7: invokevirtual #4 // Method sayHello:()V
10: return
索引0
,即new
字节代码指令,创建一个新对象,并将对该对象的引用推送到堆栈中。 dup
指令复制该值并将其推送到堆栈顶部。所以你现在有两个对该对象的引用。 invokespecial
使用一个,invokevirtual
使用另一个(它们弹出他们使用的参考值)。一旦完成,就不再有对象的引用,它可以被垃圾收集。