1. 程式人生 > >java虛擬機器——垃圾回收器

java虛擬機器——垃圾回收器

Serial收集器:

serial收集器是最基本的發展最悠久的收集器,這是一個單執行緒收集器,它只會使用一個CPU,一個收集執行緒去完成垃圾收集工作,更重要的是它進行垃圾收集工作時必須暫停所有的其他執行緒,直到它收集結束。暫停所有執行緒,stop the  world,在使用者看不見的情況下把使用者正常工作的執行緒給全部停止。

下圖示意了  Serial/Serial Old收集器的執行過程。

 相對優點:依然是虛擬機器執行在client模式下的預設新生代收集器,簡單而高效,單個cpu,沒有執行緒互動開銷,專心GC,獲得最高的單執行緒收集效率。

ParNew收集器:是serial的多執行緒版本。

 優點:除了多執行緒收集,與serial收集器並沒有太多創新,是server模式下的首選新生代收集器,一個與效能無關但很重要的原因是:除了serial之外,只有它能與CMS收集器配合工作。

Parallel Scavenge 收集器:一個新生代收集器,copying演算法,並行多執行緒收集器。吞吐量優先收集器

其他的收集器只是儘可能的縮短垃圾收集時使用者執行緒停頓的時間,而parallel Scavenge收集器的目標是達到一個可控吞吐量,

吞吐量=執行使用者程式碼時間/(使用者時間+GC時間),提供兩個引數來精確控制吞吐量①控制最大垃圾收集時間

-XX:MaxGCPauseMillis,②直接設定吞吐量大小, -XX:GCTimeRatio。

不要認為把 MaxGCPauseMillis這個值設定的小一些,就能使垃圾收集的速度變得更快。GC停頓時間的縮短使以犧牲吞吐量和新生代空間的大小來換取的。

Parallel Scavenge 收集器還有一個引數 -XX:+UseAdaptiveSizePolicy 這是一個開關引數,開啟之後就不需要指定新生代大小,eden,survivor的比例,等細節的引數,它會根據當前系統執行的情況,動態調整這些引數,提供最合適的停頓時間或者最大吞吐量,稱之為GC自適應策略,是parallel scavenge與parNew的一個重要區別。

Serial Old收集器:是serial收集器的老年代版本,使用Mark-Compact,單執行緒收集器,主要意義在於給client模式下的虛擬機器使用

①在jdk1.5之前版本與parallel Scavenge 搭配 ②作為CMS收集器的後備預案

Parallel Old收集器:是parallel scavenge 收集器的老年代版本,多執行緒收集器,Mark-compact ,在此之前如果新生代選擇parallel  scavenge收集器,那麼老年代除了serial old沒有別的收集器可以選擇。由於老年代serial old 收集器在服務端應用效能的拖累,使用parallel  scavenge收集器也未必能在整體應用上獲取吞吐量最大化的效果,直到parallel old的出現,“吞吐量優先”收集器才有了名副其實的應用組合。

CMS收集器  concurrent Mark sweep 是一種獲取最短回收停頓時間為目標的收集器,基於Mark-Sweep演算法,主要分為四個步驟

①初始標記②併發標記③重新標記④併發清除

其中初始標記和重新標記仍需要stop  the  world

初始標記:僅僅標記一下GCRoots能直接關聯到的物件,速度很快

併發標記:進行GCRoots  tracing 過程

重新標記:為了修正併發標記期間,使用者執行緒執行而導致標記變動的一部分物件的記錄

由於過程中耗時最長的併發標記和併發清除過程收集器執行緒與使用者執行緒一起工作,所以總體上來說CMS的記憶體回收與使用者執行緒一起併發執行的。

CMS對cpu資源非常的敏感,CMS預設  回收執行緒數=(cpu數量+3)/4,當cpu不足4個,比如2個,CMS對使用者執行緒影響可能變得很大,cpu還要分出一半的運算能力去執行收集執行緒。為了解決這個問題,虛擬機器提供了一種增量式併發收集器,就是在併發標記和清理的時候讓GC執行緒和使用者執行緒交替執行,儘量減少GC執行緒獨佔資源的時間,但垃圾收集時間會更長些,實踐證明i-CMS效果很一般,已經被宣告為不提倡使用。

CMS無法處理浮動垃圾(Floating Garbage),可能出現“Concurrent Mode Failure”而導致一次full  Gc。因為在併發清理的過程中還有一部分使用者執行緒在執行,會有新的垃圾不斷產生新的垃圾,CMS無法在當次處理掉它,只好留到下次處理,這一部分垃圾就是“浮動垃圾“ 在gc階段,使用者執行緒也在執行,就要有足夠的記憶體給使用者執行緒使用,因此CMS不能像其它收集器一樣老年代幾乎填滿了再進行收集,需要預留一部分空間來滿足併發收集時使用者程式執行使用。要是執行期間記憶體無法滿足程式的需要,就會出現Concurrent Mode Failue,這時候虛擬機器的後備預案,使用serial old重新對老年代的垃圾進行收集

記憶體碎片:使用-XX:CMSFullGCsBeforeCompaction,這個引數表示執行多少次不壓縮的full  gc跟著來一次帶壓縮的full  gc,預設為0

G1收集器:Garbage  first,是當前收集器技術裡面最前沿的成果之一,面向服務端應用的垃圾收集器

G1的特點:併發與並行,G1能夠充分的利用cpu多核環境下的優勢,縮短停頓時間,G1使用併發的方式讓java程式繼續執行。可預測停頓,這是G1相對於CMS的一大優勢,能讓使用者明確的指定在一個長度為M毫秒的時間內消耗在GC上的時間不超過N毫秒,這幾乎是實時java垃圾收集器的特徵了

G1收集器記憶體的佈局和其它收集器有很大的差別,它將整個java堆分成多個大小相當的獨立區域(Region)雖然還保留了新生代和老年代,但是新生代和老年代不再是物理隔離,它們是一部分region(不需要連續)的集合

G1收集器能建立可預測停頓時間模型,是因為它有計劃的避免在整個java堆進行全區域垃圾收集,G1跟蹤各個region中的垃圾堆積價值大小(回收所獲得的空間大小及回收所需要時間的經驗值)在後臺維護一張優先列表,每次根據允許收集時間,優先回收價值最大的Region,這就是G1名字的由來,這種方式保證了G1收集器在有限的時間內儘可能的高的收集效率

Regin之間的物件引用以及其它收集器中新生代與老年代之間物件的引用虛擬機器都是採用Rembered Set來避免全域性掃描,G1中每一個region'都有一個rembered  set與之對於,當虛擬機發現程式對reference型別的資料進行寫操作的時候,會檢查reference引用的對像是否處於不同的region之中,若是,就把引用資訊記錄到被引用物件所屬的region的rembered set中,當回收記憶體時GC根節點列舉範圍加入Remember set即可保證不讀全堆掃描,也不會遺漏