2012-01-20 37 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來說不可見,它只能看到寄存器,堆棧,全局變量和從堆塊到其他堆塊的引用。所以範圍是不相關的。