【對象的生死判定】

垃圾回收

JAVA有一個很大的好處就是,不用自己管理內存,虛擬機幫助開發者完成了這些操作。所以這是好是壞呢?不敢苟同。

對象生死

垃圾的定義:垃圾回收肯定是要知道怎麼定義垃圾。簡單點說就是,已經被用過了,並且不會再用了,而且還在內存裏面的對象,就是垃圾。因爲他佔着資源。
如何判斷垃圾:現在常用的兩種方法,引用計數法和可達性分析。
引用計數:這個其實是一個很不錯的方法,思想也很簡單,如果一個對象被引用了,那麼就給它的生命力++,如果引用它的人生命結束了,那麼它的生命就減一。最後看看誰生命值是0,那麼就判定他是垃圾。嗯,不錯的一個方案,實現起來也很簡單。
引用計數存在的問題
在這裏插入圖片描述但是在這種情況下,就不是很好了,這種情況被稱之爲循環引用,A引用了B,B又引用了A,那麼他倆的生命力得到了對方的加持,一直不爲0,就一直存活。
可達性分析:其實這種情況,抽象一下就是出現了環路。從圖論的角度來看,這個引用關係構成的圖應該是一個DAG(有向無環圖),一旦環路存在,那麼就會出現上述問題。繼續考慮,其實都考慮到圖論這來了,那麼這個問題的解就顯而易見了:所有的應用關係構成了有向圖,如果有些連通分量裏面的所有點都沒被用過,那麼這個連通分量可以被丟棄。
在這裏插入圖片描述比如這個圖,左邊存在環路,右邊也可能存在。虛擬機中有一個GC ROOT,即使這些點的計數不爲0,當GC ROOT不可達的時候,那麼這些連通分量裏面的對象依然會被回收。

死緩

再給個機會:如果計數爲0或者不可達就要被判定死刑了嗎?似乎不太合理,因爲太絕情了。因爲雖然在當前狀態不可達或者沒有人引用,沒準下一狀態裏面就有人用了呢?這是很可能的,如果直接銷燬掉用了再創建這其實還是比較浪費的,因爲做了不必要的工作,但是一直呆在內存裏也不是很合適,所以虛擬機決定再給對象一個機會,如果對象能夠實現自我的救贖,那麼就不判死刑了,否則就銷燬掉。虛擬機的設計充滿了人道主義
死緩:當對象不可達,就進入了死緩的狀態。
第一次篩選:進入死緩狀態的對象,虛擬機會進行第一次篩選,篩選的條件是判斷該對象有沒有必要執行finalize()方法,如果當前對象沒有覆蓋finalize()方法,或者該方法被虛擬機調用過一次了,虛擬機就會認爲沒有必要執行。對於沒必要執行的對象,額,不好意思,那就是真的死刑了。對象直接被銷燬
第二次篩選:對於有必要執行finalize()方法的對象,會被丟人一個叫做F_Queue隊列中,之後,虛擬機會創建一個Finalizer線程然後開始來銷燬對象,當然這個線程優先級很低,並且不保證能夠執行完。在死亡即將到來之時,如果隊列中的對象能夠在這個過程中和GC ROOT 可達的對象建立連接,那麼成功自我救贖。虛擬機在第二次標記時,會把它移出隊列,其他的也是死刑。
有趣的是,finalize()方法只會被調用一次,也就是這種自我救贖的方式只能用一次,第二次被就沒用了。一般不建議使用finalize()方法去拯救對象,因爲它的開銷是比較大的。

以上就是虛擬機對對象生死的判定方法,下一篇講述垃被垃圾回收的具體機制。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章