2012-01-20 27 views
10

我正在与我的应用程序的内存问题作斗争,并试图让我的头围绕垃圾收集。如果我有下面的代码:究竟是什么时候可用于垃圾收集的对象?

public void someMethod() { 
    MyObject myObject = new MyObject(); 
    myObject.doSomething(); //last use of myObject in this scope 
    doAnotherThing(); 
    andEvenMoreThings(); 
} 

所以我的问题是,将myObject可用于垃圾收集myObject.doSomething()这是一次使用这种对象,或someMethod()完成后后,它散发出来的范围是什么?即是否足够聪明地看到垃圾收集,尽管局部变量仍在范围之内,其余代码将不会使用它?

+1

我想你在错误的上下文中使用'dereferenced'。 – isah

+1

仅仅因为垃圾收集器认为它没有被使用并不代表它会马上选择释放它 - 你不应该编写依赖于不可预知事件行为的代码;)如果你有内存问题那么你可能会错误地引用一些东西:( – deanWombourne

+0

嗯,谢谢isah,我认为你是对的,我会更新标题的问题 –

回答

4

“从何而来超出范围”

public void someMethod() { 
    MyObject myObject = new MyObject(); 
    myObject.doSomething(); //last use of myObject in this scope 
    myObject = null; //Now available for gc 
    doAnotherThing(); 
    andEvenMoreThings(); 
} 
+0

它会发生在第4行,因为你已经明确地取消引用 myObject = null; //现在可用于gc –

+0

是的,这是正确的, – Farmor

+1

在问题中虽然它会在卷曲后结束大括号,因为没有取消引用.. –

2

后局部范围超出。因为对象可以被重用并且可以在本地范围内生存。即。它被标记为gc。但实际上没有。

2

代码优化可能会注意到最后使用其中的myObject是,使之可用于垃圾回收有,但技术上这将是直到变量不再是指它(通过被分配到别的东西),或者去超出范围。

+0

我不认为这是JLS实际允许的 - 或者至少热点不这样做。实际上,.NET确实允许我们[GC.KeepAlive](http://msdn.microsoft.com/en-us/library/system.gc.keepalive.aspx)避免收集对象(例如计时器)副作用比我们想要的要早。至少在Java中,我从未偶然发现任何会让我感到意外的事情。 – Voo

+0

有趣。通过代码优化,你的意思是JVM执行,GC执行还是代码编译? –

4

你可以做的最好的事情就是把你的代码放在一个有延迟的循环中,然后连接一个探查器。

如果您使用的是更高版本的Java,那么JVisualVm就是标准配置。

如果您使用的是Windows和JAVA_HOME设置

%JAVA_HOME%/ bin中/ jvisualvm

这将启动一个分析器,你可以看到正在收集什么物品,什么都没有。在我看来,这是成为程序员和查找内存泄漏的乐趣的重要部分。

希望这有助于

+0

+1分析器建议 – helios

4

顺便说一下在以后的Java 6中,存在的escape analysis类型,其中JVM可以发现你的MyObject的实例不会离开的方法,因此它甚至可以把它完全基于堆栈和你根本不需要任何GC。

3

所以我的问题是,myObject.doSomething(),这是最后一次使用这个对象的,或者的someMethod()完成它从何超出范围后后将MYOBJECT可用于垃圾收集?

前者。

I.e.是否足够聪明地看到垃圾收集,尽管局部变量仍在范围之内,其余代码将不会使用它?

作用域对GC来说不可见,它只能看到寄存器,堆栈,全局变量和从堆块到其他堆块的引用。所以范围是不相关的。