1. 程式人生 > >java GC 幾種演算法

java GC 幾種演算法

當一個物件不再被引用的時候,記憶體回收它佔領的空間,以便空間被後來的新物件使用。除了釋放沒用的物件,垃圾收集也可以清除記憶體記錄碎片。

1、 引用計數法(Reference Counting Collector)

    引用計數法是唯一沒有使用根集的垃圾回收的法,該演算法使用引用計數器來區分存活物件和不再使用的物件。一般來說,堆中的每個物件對應一個引用計數器。當每一次建立一個物件並賦給一個變數時,引用計數器置為1。當物件被賦給任意變數時,引用計數器每次加1當物件出了作用域後(該物件丟棄不再使用),引用計數器減1,一旦引用計數器為0,物件就滿足了垃圾收集的條件。
    基於引用計數器的垃圾收集器執行較快,不會長時間中斷程式執行,適宜地必須 實時執行的程式。但引用計數器增加了程式執行的開銷,因為每次物件賦給新的變數,計數器加1,而每次現有物件出了作用域生,計數器減1。


ps:用根集的方法(既有向圖的方法)進行記憶體物件管理,可以消除迴圈引用的問題.就是說如果有三個物件相互引用,只要他們和根集是不可達的,gc也是可以回收他們.根集的方法精度很高,但是效率低.計數器法精度低(無法處理迴圈引用),但是執行效率高.

2、tracing演算法(Tracing Collector)

    tracing演算法是為了解決引用計數法的問題而提出,它使用了根集的概念。基於tracing演算法的垃圾收集器從根集開始掃描,識別出哪些物件可達,哪些物件不可達,並用某種方式標記可達物件,例如對每個可達物件設定一個或多個位。在掃描識別過程中,基於tracing演算法的垃圾收集也稱為標記和清除 (mark-and-sweep)垃圾收集器。


3、compacting演算法(Compacting Collector)

    為了解決堆碎片問題,基於tracing的垃圾回收吸收了Compacting演算法的思想,在清除的過程中,演算法將所有的物件移到堆的一端,堆的另一端就變成了一個相鄰的空閒記憶體區,收集器會對它移動的所有物件的所有引用進行更新,使得這些引用在新的位置能識別原來 的物件。在基於Compacting 演算法的收集器的實現中,一般增加控制代碼和控制代碼表。

4、copying演算法(Coping Collector)

    該演算法的提出是為了克服控制代碼的開銷和解決堆碎片的垃圾回收。
    將記憶體分為兩個區域(from space和to space)。所有的物件分配記憶體都分配到from space。在清理非活動物件階段,把所有標誌為活動的物件,copy到to space,之後清楚from space空間。然後互換from sapce和to space的身份。既原先的from space變成to sapce,原先的to space變成from space。每次清理,重複上述過程。

    優點:copy演算法不理會非活動物件,copy數量僅僅取決為活動物件的數量。並且在copy的同時,整理了heap空間,即,to space的空間使用始終是連續的,記憶體使用效率得到提高。
    缺點:劃分from space和to space,記憶體的使用率是1/2。收集器必須複製所有的活動物件,這增加了程式等待時間。

5、generation演算法(Generational Collector)

    來自IBM的一組統計資料:98%的java物件,在建立之後不久就變成了非活動物件;只有2%的物件,會在長時間一直處於活動狀態。

     (1)young generation

    年輕代分三個區。一個Eden區,兩個Survivor區。大部分物件在 Eden區中生成。當Eden區滿時,還存活的物件將被複制到Survivor區(兩個中的一個),當這個Survivor區滿時,此區的存活物件將被複制到另外一個Survivor區,當這個Survivor區也滿了的時候,從第一個Survivor區複製過來的並且此時還存活的物件,將被複制到 tenured generation。需要注意,Survivor的兩個區是對稱的,沒先後關係,所以同一個區中可能同時存在從Eden複製過來物件,和從前一個 Survivor複製過來的物件,而複製到年老區的只有從第一個Survivor去過來的物件。而且,Survivor區總有一個是空的。
    young generation的gc稱為minor gc。經過數次minor gc,依舊存活的物件,將被移出young generation,移到tenured generation

    (2)tenured generation

    生命週期較長的物件,歸入到tenured generation。一般是經過多次minor gc,還 依舊存活的物件,將移入到tenured generation。(當然,在minor gc中如果存活的物件的超過survivor的容量,放不下的物件會直接移入到tenured generation)
tenured generation的gc稱為major gc,就是通常說的full gc。
    採用compaction演算法。由於tenured generaion區域比較大,而且通常物件生命週期都比較長,compaction需要一定時間。所以這部分的gc時間比較長。
    minor gc可能引發full gc。當eden+from space的空間大於tenured generation區的剩餘空間時,會引發full gc。這是悲觀演算法,要確保eden+from space的物件如果都存活,必須有足夠的tenured generation空間存放這些物件。

    (3)permanent generation

    該區域比較穩定,主要用於存放classloader資訊,比如類資訊和method資訊。
對於spring hibernate這些需要動態型別支援的框架,這個區域需要足夠的空間。(這部分空間應該存在於方法區而不是heap中)。

6、adaptive演算法(Adaptive Collector)

    在特定的情況下,一些垃圾收集演算法會優於其它演算法。基於Adaptive演算法的垃圾收集器就是監控當前堆的使用情況,並將選擇適當演算法的垃圾收集器。