Java虛擬機知識整理——垃圾的判斷

說起垃圾收集(GarbageCollection,GC),大部分人都把這項技術當做Java語言的伴生產物。事實上,GC的歷史比Java久遠,1960年誕生與MIT的Lisp是第一門真正使用動態分配和垃圾收集技術的語言。
經過半個多世紀的發展,目前內存的動態分配與內存回收技術已經相當成熟,一切看起來都進入了“自動化”時代,爲什麼還需要了解GC和內存分配呢?答案很簡單:當需要排查各種內存溢出、內存泄露問題時,當垃圾手機成爲系統達到更高併發量的瓶頸時,我們就需要對這些“自動化”的技術實施必要的監控和調節。

對象死了嗎?

垃圾收集器在對堆進行回收前,需要判斷對象那些還“存活”着,哪些已經“死去”。然後才能對“死去”的對象進行回收。

引用技術算法

引用計數算法是這樣的:給對象中添加一個引用計數器,每當有一個地方引用它時,計數器值就加1;當引用失效時,計數器值就減1;任何時刻計數器爲0的對象就是不可能再被引用的。
引用計數算法的實現簡單,判定效率也很高,在大部分情況喜愛它都是一個不錯的算法,但是至少主流的Java虛擬機裏面沒有選用醫用計數算法來管理內存,其中最主要的原因是它很難解決對象之間相互循環引用的問題。

可達性分析算法

在主流的商用程序語言的主流實現專攻,都是稱通過可達性分析來判定對象是否存活的。這個算法的基本思想是通過一系列的成爲“GC Roots”的對象作爲起始點,從這些節點開始向下搜索,搜索鎖走過的路徑稱爲引用鏈,當一個對象到GC Roots沒有任何因用力按相連接時則證明此對象是不可用的。
在java語言中,可作爲GC Roots的對象包括下面幾種:
1.虛擬機棧(棧幀中的本地變量表)中引用的對象。
2.方法去中金泰屬性引用的對象。
3.方法區中常量引用的對象。
4.本地方法棧中JNI(即一般說的Native方法)引用的對象。

我還想再搶救一下

及時在可達性分心算法中的不可達對象,也並非是“Facebook(非死不可)”的,這時候他們暫時處於“緩刑”階段,如果還想‘再搶救一下’還可以用finalize()標記。因爲真正宣告一個對象死亡,至少要經歷兩次標記過程:第一次標記有沒有與GC Roots想鏈接的引用鏈,那它將會被第一次標記並開始第一次篩選,帥選的條件是此對象是否有必要執行finalize()方法。當對象沒有覆蓋finalize()方法,或者finalize()已經被虛擬機調用過,虛擬機將這兩種情況都視爲“沒必要執行”。但是finalize()方法調用不一定會成功,如果不成功,那麼對象也只能“死去”。
所以,簡單來說finalize()可以讓要“死去”的對象“再搶救一下”,如果“搶救”成功,就可以多存活一會,如果“搶救”失敗也只能死亡。

回收方法區

方法區的垃圾手機主要回收兩部分內容:廢棄常量和無用的類。
要判斷一個常量是否是“廢棄變量”比較簡單,而要判定一個類是否是“無用的類”的條件則相對苛刻許多。需要滿足一下三個條件:
1.該類所有的實例都已經被回收也就是Java堆中不存在該類的任何實例。
2.加載該類的ClassLoader已經被回收。
3.該類對應的java.lang.Class對象沒有在任何地方被引用,無法在任何地方通過反射訪問該類的方法。
滿足上面的三個條件,僅僅是可以回收,會不會回收還要取決於虛擬機的其他判斷是否通過。因爲類是否無用相對來說需要更多的條件。

所以就是垃圾了

對象被判斷爲垃圾,沒有進行成功的“搶救”,就說明對象可以被回收了。當垃圾回收的線程開始運行的時候就會開始回收這些垃圾。

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