1. 程式人生 > >第三章:垃圾回收器:垃圾回收器的兩種算法

第三章:垃圾回收器:垃圾回收器的兩種算法

是否 div 搜索路徑 word position 其他 範圍 ava 對象實例

垃圾回收需要考慮三個問題: 哪些內存需要回收? 什麽時候回收? 如何回收? JVM中程序計數器、虛擬機棧、本地方法三個區域隨線程而生,隨線程而死,這三個區域的內存分配和回收都具有確定性,在這個幾個區域不需要過多考慮回收的問題,因為方法結束或者線程結束時,內存自然就隨著回收了。 而Java堆和方法區則不一樣,一個接口中的多個實現類需要的內存可能不一樣,一個方法中的不同分支需要的內存也可能不一樣,我們只能在運行期間才能知道會創建哪些對象,這部分內存的分配和回收時動態的,垃圾收集器主要關註的是這部分區域。 在Java堆中存放著java世界幾乎所有的對象實例,垃圾回收器在對堆進行回收前,首要意見事就是確定哪些還存活著,哪些已經死去(即再不可能被任何途徑使用的對象)
  • 引用計數器算法
給對象中添加一個引用計數器,每當有一個地方引用它時,計時器就加1,當引用失效時就減1,任何時刻計時器為0的對象就是不可能再被使用的。 引用計數器的優點:實現簡單; 缺點:無法解決互相引用的問題 類似A實例引用B實例,B實例引用A實例,這種情況A、B兩個實例的引用計數器都不為0,永遠無法回收。
  • 可達性分析算法
這個算法的思路就是通過一系列稱為GC Root的對象作為起始點,從這些起始點開始向下搜索,搜索路徑所走過的路徑叫做引用鏈,當一個對象到GC root沒有任何引用鏈相連時,則證明此對象時不可能再被使用的,可以將這些對象定義為可回收的對象。 在java語言中,可作為GC Roots的對象包括以下四種: 虛擬機棧(棧幀中的本地變量表)中的引用對象 方法區中類靜態屬性引用的對象 方法區中常量引用對象 苯菲方法棧中JNI(即一般說的Native方法)引用的對象 無論是引用計數器還是可達性分析算法都是與對象是否存在活著的引用有關。 JDK1.2之前java中的引用的定義為如果reference雷丁的數據中存儲的數值代表的是另一塊內存的起始地址,就稱為這塊內存代表著一個引用。 JDK1.2之後,Java對引用的概念進行了擴充,將引用分為強引用、軟引用、弱引用、虛引用四種:
  • 強引用:可以理解為Object ob = new Object(),這種代碼中普遍存在的引用,只要強引用還在,垃圾回收器就不會進行回收;
  • 軟引用:用來描述一些還有用但是並非必需的對象,對於軟引用關聯的隊盎,在系統將要發生內存溢出異常前,將會把這些對象列進回收範圍值周進行二次回收,如果這次回收還沒有足夠的內存,才會拋出內存溢出異常。
  • 弱引用:用來描述非必要的對象的,但是它的強度比軟引用更弱一些,被弱引用關聯的對象之鞥呢存活到下一次垃圾收集發生之前,當垃圾回收器工作時,無論當前的內存是否足夠,都會回收掉被弱引用關聯的對象。
  • 虛引用:它是最弱額的一種引用關系,一個對象是否是虛引用完全不會對其生命時間構成影響,也無法通過虛引用來取得一個對象實例。為一個對象設置虛引用關聯的唯一目的就是能在這個對象被收集器回收時收到一個系統通知。
即使可達性算法中不可達的對象,也並非時“非死不可”,這時候他們這哪是處於“緩刑”節點,要真正宣告一個對象死亡,至少要經理兩次標記過程:如果對象在進行可達性分析後發現沒有雨GC Roots相連的引用鏈,那麽它將會被第一次標記並且進行一次篩選,篩選的條件是此對象是否有必要執行finalize方法。當對象沒有覆蓋finalize方法或者finalize方法已經被虛擬機調用過了,虛擬機將這種情況視為“沒有必要執行”。 如果一個對象被判定為有必要執行finalize方法,那麽這個對象將會放置在一個叫做F-Queue的隊列中,並在稍後有一個由虛擬機自動建立的、低優先級的Finalizer線程去執行它,這裏所謂的執行是指虛擬機會觸發這個方法,當時並不會承諾登臺它運行結束,這樣做的原因是防止F-Queue隊列中其他對象永遠處於等待甚至發生了死循環,從而影響整個內存回收奔潰。 finalize是對象逃脫死亡的最後一次機會。如果在進行第二次標記時,對象要在finalize中成功拯救自己,只要重新與引用鏈上的任何一個對象建立關聯即可。 需要註意的一點是:任何一個對象的finalize方法都只會被系統自動調用一次。

第三章:垃圾回收器:垃圾回收器的兩種算法