2010-11-09 71 views
13

我是一名进入Java世界的C++程序员。我无法摆脱让Java垃圾收集器进行清理的不良感觉。本地变量上的垃圾回收

例如,这段代码如何在Java中运行?

public void myFunction() { 
    myObject object = new myObject(); 
    object.doSomething(); 
} 

当myFunction()退出时,局部变量对象是否会被删除?

在退出之前是否必须将对象设置为null,还是会超出范围并被GC删除?或者,最糟糕的情况是,它会像C++一样泄漏吗?

回答

23

它将被垃圾收集在它不再使用的某个点上。我相信在Java的当前实现中,它实际上会一直持续到方法结束,而.NET中的垃圾收集器更具侵略性。 (我不知道在Java中是否有任何保证,通常只有想要这个局部变量在调试时保持超出最后可能的读数。)

但是不, t需要将变量设置为null,这样做会损害可读性。

该方法退出后,该对象不可能立即收集垃圾;这取决于GC运行的时间......当然,如果有其他任何东西持有对该对象的引用,它可能无论如何都不符合垃圾回收的条件。不要忘记,变量的值只是一个引用,而不是对象本身。 (这可能需要一段时间才能习惯来自C++。)

+0

在之前的实现中,直到方法结束才会真正持久化?这将是一种奇怪的... – 2010-11-09 20:25:58

+2

@ Erick:我更努力避免*未来*实现将保留本地变量作为“根”的保证。 .NET CLR绝对不会,实际上一个对象可以被垃圾回收*,而一个实例方法仍然在执行“in”它*,只要GC知道什么都不会引用它的任何字段。 – 2010-11-09 20:27:14

+0

@Erick如果'doSomething()'不使用对象的任何其他字段或方法,或者可以将JIT编码以便将所有字段放入寄存器并将所有方法内联,则可以在' doSomething()'完成,更不用说'myFunction()'。唯一的标准是代码的含义是否改变。 – 2010-11-09 20:32:20

1

它将超出范围。在Java中,当没有人指向一个对象时,它将被垃圾回收或至少可用于垃圾收集。无需在此处将其设置为空。如果你的对象在你的应用程序中生存,有时需要将对象引用设置为null,但是它所包含的引用需要进行垃圾回收。在这种情况下,您正在选择发布参考。

+2

(-1代表作用域部分,变量作用域和对象生命周期在Java中根本不相关,第二部分不太正确,尽管标准是可达性而不是缺少引用 - 如果两个对象指向每个对象其他,但都不能从任何其他物体到达,那么即使有人指着它们也会收集垃圾) – 2010-11-09 20:28:52

+0

有趣的感谢 – 2010-11-09 20:38:51

2

我遇到这样的代码:

{ 
    final List myTooBigList = new ArrayList(); 
    ... overfill the list 
} 
somethingRunOutOfMemory(); 

somethingRunOutOfMemory(),因为myTooBigList不GCable,尽管不在范围内了。

和C一样,局部变量位于堆栈旁边。 堆栈指针为scope中的局部变量保留了所需的空间。 堆栈重用时,块的局部变量变为GCable。 当超出范围时,指针立即根据新的本地变量移回。

他们GCable后:

try { } catch : after exit by catch because catch reuses stack 
for { } : after exit loop condition because evaluation reuses stack 
while { }: after exit loop condition because evaluation reuses stack 
{ } followed by any local declaration that reuses stack 

他们不是GCable后:

try { } finally 
try { } catch : after nothing caught 
for { } : after break 
while { } : after break 
do { } while : after loop condition 
if { } 
{ } not followed by a local declaration 

如果我想有一个地方是GCable我写:假的

{ 
    final List myTooBigList = new ArrayList(); 
    ... overfill the list 
} 
Object fake = null; 
somethingDoesntRunOutOfMemory(); 

矫揉造作将堆栈指针移回并使myTooBigList GCable。令人惊讶的是(至少在我测试的jvm中)我们必须明确地重用堆栈。一旦块被退出,预计局部变量会变成GCable,但我想这是对性能的妥协。这会使字节码复杂化很多。

注意:要测试一个变量是否为GCable,我运行GC,然后将WeakReference(我的变量)与null进行比较。

final WeakReference gctest; 
{ 
    final List myTooBigList = new ArrayList(); 
    gctest = new WeakReference(myTooBigList); 
    ... overfill the list 
} 
Object fake = null; 
System.gc(); 
assert gctest.get() == null;