垃圾收集器是垃圾回收算法(标記-清除算法、複制算法、标記-整理算法)的具體實作,不同商家、不同版本的JVM所提供的垃圾收集器可能會有很在差别.
這裡寫圖檔描述
圖中展示了7種不同分代的收集器:
Serial、ParNew、Parallel Scavenge、Serial Old、Parallel Old、CMS、G1;
而它們所處區域,則表明其是屬于新生代收集器還是老年代收集器:
新生代收集器:Serial、ParNew、Parallel Scavenge;
老年代收集器:Serial Old、Parallel Old、CMS;
整堆收集器:G1;
兩個收集器間有連線,表明它們可以搭配使用:
Serial/Serial Old、Serial/CMS、ParNew/Serial Old、ParNew/CMS、Parallel Scavenge/Serial Old、Parallel Scavenge/Parallel Old、G1;
Serial收集器
Serial收集器是單線程收集器,是分代收集器。它進行垃圾收集時,必須暫停其他所有的工作線程,直到它收集結束(Stop TheWorld)。
新生代:單線程複制收集算法;
老年代:單線程标記整理算法。
Serial一般在單核的機器上使用,是Java 5非服務端JVM的預設收集器,參數-XX:UseSerialGC設定使用。
優勢:對于單CPU環境來說,Serial收集器沒有線程互動的開銷,專心做垃圾收集可以獲得最高的單線程收集。Serial收集器對于在Client模式下的虛拟機是一個很好的選擇。
ParNew收集器
ParNew/Serial Old組合收集器運作示意圖如下:
ParNew收集器其實就是Serial收集器的多線程版本。新生代并行,老年代串行;新生代複制算法、老年代标記-整理
參數控制:
-XX:+UseConcMarkSweepGC":指定使用CMS後,會預設使用ParNew作為新生代收集器;
-XX:+UseParNewGC":強制指定使用ParNew;
-XX:ParallelGCThreads":指定垃圾收集的線程數量,ParNew預設開啟的收集線程與CPU的數量相同;
優勢:ParNew收集器是許多運作在server模式下的虛拟機中首選的新生代收集器,一個重要的原因是,隻有ParNew和Serial收集器能和CMS收集器共同工作。無法與JDK1.4中存在的新生代收集器Parallel Scavenge配合工作,是以在JDK1.5中使用CMS來收集老年代的時候,新生代隻能選擇ParNew和Serial。
ParNew收集器在單CPU環境中不比Serial效果好,甚至可能更差,兩個CPU也不一定跑的過,但随着CPU數量的增加,性能會逐漸增加。預設開啟的收集線程數與CPU數量相同。在CPU數量很多的情況下,可以使用-XX:ParallelGCThreads參數來限制線程數。
Parallel Scavenge收集器
Parallel Scavenge收集器是一個新生代的手機器,使用的是複制算法的收集器,而且也是多線程的收集器。
Parallel Scavenge收集器,目标達到一個可控制的吞吐量,使用-XX:MaxGCPauseMillus參數控制垃圾停頓時間,使用-XX:GCTimeRatio參數控制吞吐量。Parallel Scavenge收集器設定-XX:UseAdaptiveSizePolicy參數,虛拟機會根據目前系統的運作情況收集性能監控資訊,動态調整這些參數以提供最合适的停頓時間或者最大吞吐量(GC自使用的調節政策)。
自适應調節政策也是Parallel Scavenge收集器和ParNew收集器一個重要的差別。
Serial Old收集器
Serial收集器的老年代版,它同樣是一個單線程收集器,使用标記–整理算法。收集器的意義在于給Client模式下的虛拟機使用。如果在Server模式下,那麼它主要有兩大用途:一種是在jdk1.5以及之前的版本中與Parallel Scavenge收集器搭配使用,另一種用途是作為CMS收集器的後預案,在并發收集發生Concurrent Mode Failure時使用。工作流程圖如下:
Parallel Old 收集器
Parallel Scavenge收集器的老年代版,使用多線程與标記–整理算法。這個收集器在jdk1.6中才開始提供的,直到Parallel Old 收集器出現後,“吞吐量優先”收集器終于有了比較名副其實的應用組合,在注重吞吐量以及CPU資源敏感的場合,都可以優先考慮Parallel Scavenge加 Parallel Old收集器
CMS收集器
一種以擷取最短回收停頓時間為目标的收集器。目前很大一部分的java應用集中在網際網路站或者B/S系統的服務端上,這類應用尤其重視服務的響應速度,希望系統停頓時間最短,以給使用者帶來較好的體驗。CMS收集器就非常符合這類應用的需求。CMS收集器是基于“标記-清除”算法實作的,主要分為4個步驟。
初始标記(CMS inital mark):需要“stop the world”,但隻标記一下GC Roots能直接關聯的對象,速度很快。
并發标記(CMS concurrent mark):是GC Roots Tracing的過程,花費時間長
重新标記(CMS remark):*需要“stop the world”,是為了修正并發标記期間因使用者程式繼續運作而導緻标記産生變動的那一部分對象的标記記錄,這個階段時間一般會比初始标記階段稍長一些,但遠比并發标記的時間短。
并發清除(CMS concurrent sweep):是并發清除無用對象。
缺點:
CMS收集器對CPU資源非常敏感。在并發階段,它雖然不會導緻使用者線程停頓,但是因為占用了一部分CPU資源而導緻應用程式變慢,總吞吐量就會降低。CMS預設啟動的回收線程數為(CPU數量+3)/4。當CPU的個數少于2個的時候,CMS對使用者程式的影響可能會變得很大。
CMS收集器無法處理浮動垃圾(floating garbage),可能會出現concurrent mode failure導緻另一次full gc的産生。在CMS的并發清理階段,由于程式還在運作,垃圾還會不斷産生,這一部分垃圾出現在标記過程之後,CMS無法在本次收集中處理掉它們,隻好留到下一次GC再處理。這種垃圾稱為浮動垃圾。同樣由于CMS GC階段使用者線程還需要運作,即還需要預留足夠的記憶體空間供使用者線程使用,是以CMS收集器不能像其他收集器那樣等到老年代幾乎完全被灌滿了再進行收集而需要預留一部分空間提供并發收集時的程式運作使用。預設設定下 CMS收集器在老年代使用了68%的空間後就會被激活。這個值可以用-XX:CMSInitiatingOccupancyFraction來設定。要是CMS運作期間預留的記憶體無法滿足程式需要,就會出現concurrent mode failure,這時候就會啟用Serial Old收集器作為備用進行老年代的垃圾收集。
空間碎片過多(标記-清除算法的弊端),CMS是基于标記-清除算法來實作的回收器,提供-XX:+UseCMSCompactAtFullCollection參數,應用于在FULL GC後再進行一個碎片整理過程。-XX:CMSFullGCsBeforeCompaction,多少次不壓縮的full gc後來一次帶壓縮的。
G1收集器
G1收集器(Garbage-First):是當今收集器技術發展的最前沿的成果之一,G1是一款面向伺服器端應用的垃圾收集器。 使用G1收集器時,java堆的記憶體布局就與其他收集器有很大差别,它将真個java堆劃分為多個大小相等的獨立區域(Region),雖然還保留新生代與老年代的概念,但新生代與老年代不再試實體隔離的了,他們都是一部分Region(不需要連續)的集合。G1具備如下特點:
并行與并發:G1能充分利用多CPU、多核環境下的硬體優勢,使用多個CPU(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(RTSJ)的垃圾收集器的特性了。
初始标記(Initial Marking):标記GC Roots能夠直接關聯到的對象,并且修改TAMS的值,能在正确可用的Region中建立對象,這階段需要停頓線程,而且耗時很短。
并發标記(Concurrent Marking):從GC Roots開始堆中對象進行可達性分析,找出存活的對象,這個時間耗時比較長,但可與使用者程式并行執行。
最終标記(Final Marking):為了修正和正在并發标記期間因使用者程式繼續運作而導緻标記産生變動的那一部分沒有标記記錄,虛拟機将這一段對象變法記錄線上程Rememberred Set logs裡面,最終标記階段需要把Remembered Set logs 的資料合并到Remembered Set中,這階段需要停頓線程,但是可并發執行。
篩選回收(Live Data Counting and Evacuation):對各個Region的回收截止和成本進行排序,根據使用者期望的GC停頓時間來制定回收計劃,這階段可以做到和使用者程式一起并發執行,但是因為值回收一部分Region,時間是使用者可控制的,而且停頓使用者線程将大幅度提高手機效率。
這裡寫圖檔描述
Minor GC和Full GC的差別
(A)、Minor GC
又稱新生代GC,指發生在新生代的垃圾收集動作;
因為Java對象大多是朝生夕滅,是以Minor GC非常頻繁,一般回收速度也比較快;
(B)、Full GC
又稱Major GC或老年代GC,指發生在老年代的GC;
出現Full GC經常會伴随至少一次的Minor GC(不是絕對,Parallel Sacvenge收集器就可以選擇設定Major GC政策);
Major GC速度一般比Minor GC慢10倍以上;