這個收集器是一個單線程的收集器,但它的「單線程」的意義並不只僅說明它只會使用一個CPU或一條收集線程去完成垃圾收集工做,更重要的是在它進行垃圾收集時,必須暫停其餘全部的工做線程,直到它收集結束。算法
「Stop The World」,是由虛擬機在後臺自動發起和自動完成的,在用戶不可見的狀況下把用戶正常工做的線程所有停掉。多線程
Serial收集器是虛擬機運行在Client模式下的默認新生代收集器。併發
ParNew收集器其實就是Serial收集器的多線程版本,除了使用多線程進行垃圾收集以外,其他行爲包括Serial收集器可用的全部控制參數、收集算法、Stop The World、對象分配規則、回收策略等都與Serial收集器徹底同樣。佈局
ParNew收集器除了多線程收集以外,其餘與Serial收集器相比沒有太多創新之處,但它倒是許多運行在Server模式下的虛擬機中首選的新生代收集器,其中有一個與性能無關但很重要的緣由是,除了Serial收集器外,目前只有他能與CMS收集器配合工做。ParNew收集器是使用-XX:+UseConcMarkSweepGC選項後的默認新生收集器,也可使用-XX:+UseParNewGC選項來強制指定它。性能
ParNew收集器在單CPU的環境中,沒有Serial收集器效果好。固然隨着可使用的CPU的數量的增長,它對應GC時系統資源的有效利用仍是頗有好處的。它默認開啓的收集線程數與CPU的數量相同,在CPU很是多的環境下,可使用-XX:ParallelGCThreads參數來限制垃圾收集的線程數。優化
Parallel Scavenge收集器是一個新生代收集器,它也是使用複製算法的收集器,又是並行的多線程收集器。線程
Parallel Scavenge收集器的特色是它的關注點與其餘收集器不一樣,CMS等收集器的關注點是儘量的縮短垃圾收集時用戶線程的停頓時間,而Parallel Scavenge收集器的目標則是達到一個可控制的吞吐量。設計
所謂吞吐量就是CPU用於運行用戶代碼的時間與CPU總消耗時間的比值,即吞吐量 = 運行用戶代碼時間/(運行用戶代碼時間+垃圾收集時間),虛擬機總共運行了100分鐘,其中垃圾收集花掉1分鐘,那吞吐量就是99%。cdn
停頓時間越短就越適合須要與用戶交互的程序,良好的響應速度能提高用戶體驗,而高吞吐量則能夠高效率的利用CPU時間,儘快完成程序的運算任務,主要適合在後臺運算而不須要太多交互的任務。對象
Parallel Scavenge收集器提供了兩個參數用於精確控制吞吐量,控制最大垃圾收集停頓時間的-XX:MaxGCPauseMillis,吞吐量大小-XX:GCTimeRatio。
MaxGCPauseMillis參數容許的值是一個大於0的毫秒數,收集器將盡量的保證內存回收花費的時間不超過設定值。不過你們不要認爲若是把這個參數的值設置的稍小一點就能使得系統的垃圾收集速度變得更快,GC停頓時間縮短是以犧牲吞吐量和新生代空間來換取的:系統把新生代調小一些,收集300MB新生代確定比收集500MB快吧,這也直接致使垃圾收集發生的更頻繁一些,原來10秒收集一次、每次停頓100ms,如今變成5秒收集一次、每次停頓70ms。停頓時間的確在降低,但吞吐量也降下來了。
GCTimeRatio參數的值應當是一個大於0且小於100的整數,也就是垃圾收集時間佔總時間的比率,至關因而吞吐量的倒數。默認值爲99,就是容許最大1%(即1/(1+99))的垃圾收集時間。
因爲與吞吐量關係密切,Parallel Scavenge收集器收集器也常常稱爲「吞吐量優先」收集器。 自適應調節策略:-XX:+UseAdaptiveSizePolicy。這是一個開關參數,當這個參數打開以後,就不須要手工指定新生代的大小、Eden與Survivor區的比例、晉升老年代對象大小(+XX:PretenureSizeThreshold)等細節參數了,虛擬機會根據當前系統的運行狀況收集性能監控信息,動態調整這些參數以提供最合適的停頓時間或者最大的吞吐量。只須要把基本的內存數據設置好(如-Xmx設置最大堆),而後使用MaxGCPauseMillis參數(更關注最大停頓時間)或GCTimeRatio(更關注吞吐量)參數給虛擬機設定一個優化目標,具體細節參數的調節工做就由虛擬機完成了。
Serial Old收集器是Serial收集器的老年代版本,它一樣是一個單線程收集器。這個收集器的主要意義也是在於給Client模式下的虛擬機使用。在Server模式下主要有兩大用途:JDK1.5以及以前的版本中與Parallel Scavenge收集器搭配使用。做爲CMS收集器的後備預案,在併發收集發生Concurrent Mode Failure時使用。
Parallel Old是Parallel Scavenge收集器的老年代版本,使用多線程和「標記-整理」算法。
HotSpot虛擬機中第一款真正意義上的併發收集器,第一次實現了讓垃圾收集線程與用戶線程(基本上)同時工做。 CMS(Concurrent Mark Sweep)收集器是一種以獲取最短回收停頓時間爲目標的收集器。
CMS收集器是基於「標記-清除」算法實現的,運做過程分爲4個步驟:
其中,初始標記、從新標記仍然須要「Stop The World」。初始化標記僅僅只是標記一下GC Roots 能直接關聯到的對象,速度很快,併發標記階段就是進行GC Roots Tracing的過程,而從新標記階段則是爲了修正併發標記期間因用戶程序繼續運做而致使標記產生變更的那一部分對象的標記記錄,這個階段的停頓時間通常會比初始標記階段稍長一些,但遠比並發標記的時間短。
因爲整個過程當中耗時最長的併發標記和併發清除過程收集器線程均可以與用戶線程一塊兒工做,因此,整體上來說,CMS收集器的內存回收過程是與用戶線程一塊兒併發執行的。
三個明顯的缺點:
CMS默認啓動的回收線程數是(CPU數量+3)/4,也就是當CPU在4個以上時,併發回收時垃圾收集線程很多於25%的CPU資源,而且隨着CPU數量的增長而降低。可是當CPU不足4個時,CMS對用戶程序的影響就可能變的很大,若是原本CPU負載就比較大,還分出一半的運算能力去執行收集器線程,就可能致使用戶程序的執行速度突然下降了50%,讓人沒法接受。
因爲CMS併發清理階段用戶線程還在運行着,伴隨程序運行天然就還會有新的垃圾不斷產生,這一部分垃圾出如今標記過程以後,CMS沒法在當次收集中處理掉它們,只好留待下一次GC時在清理掉。這一部分垃圾就稱爲「浮動垃圾」。也是因爲在垃圾收集階段用戶線程還須要運行,那也就還須要預留有足夠的內存空間給用戶線程使用,所以CMS收集器不能像其餘收集器那樣等到老年代幾乎徹底被填滿了再進行收集,須要預留一部分空間提供併發收集時的程序運做使用。
能夠經過設置-XX:CMSInitiatingOccupancyFraction來提升觸發百分比,以便下降內存回收次數從而得到更好的性能。要是CMS運行期預留的內存沒法知足程序須要,就會出現一次「Concurrent Mode Failure」失敗,這時虛擬機將啓動後備方案:臨時啓用Serial Old收集器來從新進行老年代的垃圾收集,這樣停頓的時間就很長了。
空間碎片過多時將會給大對象分配帶來很大麻煩,每每會出現老年代還有很大空間剩餘,可是沒法找到足夠大的連續空間來分配當前對象,不得不提早觸發一次Full GC。爲了解決這個問題,CMS收集器提供了一個-XX:+UseCMSCompactAtFullCollection開關參數(默認開啓),用於在CMS收集器頂不住要進行Full GC時開啓內存碎片的合併整理過程,內存整理的過程是沒法併發的,空間碎片問題沒有了,但停頓時間不得不變長。虛擬機設計者還提供了另一個參數-XX:CMSFullGCsBeforeCompaction,這個參數是用於設置執行多少次不壓縮的Full GC後,跟着來一次帶壓縮的(默認值爲0,表示每次進入Full GC是都進行碎片整理)。
G1是一款面向服務端應用的垃圾收集器。它的使命是將來能夠替換掉CMS收集器。
特色:
並行與併發
G1能充分利用多CPU、多核環境下的硬件優點,使用多個CPU來縮短Stop The World停頓的時間,部分其餘收集器本來須要停頓Java線程執行的GC操做,G1收集器仍然能夠經過併發的方式讓Java程序繼續執行。
分代收集
與其餘收集器同樣,分代概念在G1中仍然得以保留。雖然G1能夠不須要其餘收集器配合就能獨立管理整個GC堆,但它可以採用不一樣的方式去處理新建立的對象和已經存活了一段時間、熬過屢次GC的舊對象以獲取更好的收集效果。
空間整合
與CMS的「標記-清理」算法不一樣,G1從總體來看是基於「標記-整理」算法實現的收集器,從局部(兩個Region之間)上來看是基於「複製」算法實現的,但不管如何,這兩種算法都意味着G1運做期間不會產生內存空間碎片,收集後能提供整的可用內存。這種特性有利於程序長時間運行,分配大對象時不會由於沒法找到連續內存空間而提早觸發下一次GC。
可預測的停頓
這是G1相對於CMS的另外一大優點,下降停頓時間是G1和CMS共同的關注點,但G1除了追求停頓外,還能創建可預測的停頓時間模型,能讓使用者明確指定在一個長度爲M毫秒的時間片斷內,消耗在垃圾收集上的時間不得超過N毫秒,這幾乎已是實時Java的垃圾收集器的特徵了。
使用G1收集器時,Java堆的內存佈局與其餘收集器有很大區別,它將整個Java堆劃分爲多個大小相等的獨立區域(Region),雖然還保留有新生代和老年代的概念,但新生代和老年代再也不是物理隔離的了,它們都是一部分Region(不須要連續)的集合。
G1收集器之因此能創建可預測的停頓時間模型,是由於它能夠有計劃地避免在整個Java堆中進行全區域的垃圾收集。G1跟蹤各個Region裏面的垃圾堆積的價值大小(回收所得到的空間大小以及回收所需時間的經驗值),在後臺維護一個優先列表,每次根據運營的收集時間,優先回收價值最大的Region(這也就是Garbage-First名稱的來由)。這種使用Region劃份內存空間以及有優先級的區域回收方式,保證了G1收集器在有限的時間內能夠獲取儘量高的收集效率。
在G1收集器中,Region之間的對象引用以及其餘收集器中的新生代與老年代之間的對象引用,虛擬機都是使用Remembered Set來避免全堆掃描的。G1中每一個Region都有一個與之對應的Remembered Set,虛擬機發現程序在對Reference類型的數據進行寫操做時,會產生一個Write Barrier暫時中斷寫操做,檢查Reference引用的對象是否處於不一樣的Region之中(在分代的例子中就是檢查是否老年代中的對象引用了新生代中的對象),若是是,便經過CardTable把相關引用信息記錄到被引用對象所屬的Region的Remembered Set之中。當進行內存回收時,在GC根節點的枚舉範圍中加入Remembered Set便可保證不對全棧掃描也不會有遺漏。
運做步驟:
初始標記
標記一下GC Roots能直接關聯到的對象,並修改TAMS(Next Top at Mark Start)的值,讓下一階段用戶程序併發運行時,能在正確可用的Region中建立新對象,這階段須要停頓線程,但耗時很短。
併發標記
從GC Root開始對堆中對象進行可達性分析,找出存活的對象,這階段耗時較長,但能夠與用戶程序併發執行
最終標記
最終標記階段則是爲了修正在併發標記期間因用戶程序繼續運做二致使標記產生變更的那一部分標記記錄,虛擬機將這段時間對象變化記錄在線程Remembered Set Logs裏面,最終標記階段須要把Remembered Set Logs的數據合併到Remembered Set中,這階段須要停頓線程,可是能夠併發執行。
篩選回收
最後在篩選回收階段首先對各個Region的回收價值和成本進行排序,根據用戶所指望的GC停頓時間來指定回收計劃。