1.Serial收集器
(-XX:+UseSerialGC 複製算法)
1.是一個單線程收集器,只會使用一個CPU或一條收集線程去完成垃圾收集工作
2.進行垃圾收集時,必須暫停其他所有的工作線程,直至Serial收集器收集結束爲止(“Stop The World”)
3.是HotSpot虛擬機運行在Client模式下的默認的新生代收集器
4.與其他收集器的單線程相比更加簡單高效,對於限定單個CPU的環境來說,Serial收集器由於沒有線程交互的開銷,因此可以獲得更高的單線程收集效率
2. ParNew收集器
(-XX:+UseParNewGC 複製算法)
1.ParNew收集器就是Serial收集器的多線程版本,它是一個新生代收集器
2.除了使用多線程進行垃圾收集外,其餘行爲與Serial收集器完全相同,是許多運行在Server模式下的虛擬機中首選的新生代收集器。目前只有它能與CMS收集器(老年代收集器)配合工作
3.ParNew在單cpu下性能比Serial差,但在多cpu下好,其默認開啓與cpu數量相同的線程來進行垃圾收集
3.Parallel 收集器
(-XX:+UseParallelGC 複製算法)
(-XX:+UseParallelOldGC 標記-整理算法)
1.Parallel Scavenge收集器也是一個並行的多線程新生代收集器
2.用複製算法,目的是爲了達到一個可控制的吞吐量
1.Parallel Old收集器是用在老年代的收集器,使用標記整理算法
吞吐量就是CPU用於運行用戶代碼的時間與CPU總消耗時間的比值:吞吐量=運行用戶代碼的時間/(運行用戶代碼時間+垃圾收集時間)
4.CMS收集器
(-XX:+UseConcMarkSweepGC 標記-清除算法)
概述:
CMS,全稱Concurrent Mark and Sweep,用於對年老代進行回收,目標是儘量減少應用的暫停時間,減少full gc發生的機率,利用和應用程序線程併發的垃圾回收線程來標記清除年老代
CMS並非沒有暫停,而是用兩次短暫停來替代串行標記整理算法的長暫停。
大致上分爲四步:初始標記->併發標記->重新標記->併發清除
收集週期:
1) Initial Mark 初始標記
這個階段的任務是標記老年代中被GC Roots直接可達和被年輕代對象引用的對象( The latter is important since the Old Generation is collected separately.),速度很快
這個階段也是第一次STW發生的階段
2) Concurrent Mark 併發標記
這個階段主要是通過從初始標記階段中尋找到的標記對象開始,遍歷老年代並且標記所有存活着的對象
需要注意的是,並非所有在老年代中存活的對象都會被標記,因爲程序在標記期間可能會更改引用(比如圖中的Current obj,它是併發標記階段伴隨着程序一起被刪除了引用的對象)
這個階段與應用程序共同運行
3) Concurrent Preclean 執行預清理
注: 相當於兩次 concurrent-mark. 因爲上一次concurrent-mark耗時較長,會有從新生代晉升到老年代的對象出現,將其清理掉
這也是一個併發階段,與應用程序的線程並行執行。併發標記階段與應用程序同時運行時,一些對象的引用可能會被改變,一旦這種情況發生,JVM就會標記堆上面的這塊包含了變化對象的區域(這個堆的區域被稱爲"Card",這種方式被稱爲"Card Marking")
在這個階段,這些髒對象將會被聲明,並且這些對象能夠到達的對象也會被標記。這些Card將會在上面的工作完成之後被清理掉
此外,還將執行一些必要的整理和重新標記階段的準備工作。
4) Concurrent Abortable Preclean 執行可中止預清理
這個階段也是和程序線程併發執行的。它的工作就是儘可能地進行清理工作,以減少重新標記階段的任務(即減少了STW的停頓時間)
這個階段的持續時間取決於很多因素,因爲它需要不斷地做一些相同的工作,直到滿足某個終止條件爲止(比如一定的迭代次數、一定的有效工作量、一定的時間等等)
5) Final Remark 重新標記
這個階段是第二次,也是最後一次STW。這個階段的目的是標記在老年代中所有存活下來的對象(和着3、4一起完成修復併發標記期間因用戶程序繼續運行而導致標記產生變動的那一部分對象的標記記錄的任務)
6) Concurrent Sweep 併發清除
移除未使用的對象,並且回收其佔用的空間。
7) Concurrent Reset 併發重置
重置CMS算法內部的數據結構,爲下一個週期做準備
參考文檔:https://plumbr.io/handbook/garbage-collection-algorithms-implementations/concurrent-mark-and-sweep
CMS減少停頓的原理:
標記過程分三步:併發標記是最主要的標記過程,而這個過程是併發執行的,可以與應用程序線程同時進行,初始標記和重新標記雖然不能和應用程序併發執行,但這兩個過程標記速度快,時間短,所以對應用程序不會產生太大的影響
最後併發清除的過程,也是和應用程序同時進行的,避免了應用程序的停頓。
CMS的特點:
減少了應用程序的停頓時間,讓回收線程和應用程序線程可以併發執行,它的回收並不徹底。因此CMS回收的頻率相較其他回收器要高,頻繁的回收將影響應用程序的吞吐量,空間碎片多。
CMS何時開始?
cms gc 通過一個後臺線程觸發,該線程隨着堆一起初始化,觸發機制是默認每隔2秒判斷一下當前老年代的內存使用率是否達到閾值,如果高於某個閾值的時候將激發CMS。
兩次STW的原因:
當虛擬機完成兩次標記後,便確認了可以回收的對象。但是,垃圾回收並不會阻塞程序的線程,如果當GC線程標記好了一個對象的時候,此時程序的線程又將該對象重新加入了GC-Roots的“關係網”中,當執行二次標記的時候,該對象也沒有重寫finalize()方法,因此回收的時候就會回收這個不該回收的對象。
爲了解決這個問題,虛擬機會在一些特定指令位置設置一些“安全點”,當程序運行到這些“安全點”的時候就會暫停所有當前運行的線程(Stop The World 所以叫STW),暫停後再找到“GC Roots”進行關係的組建,進而執行標記和清除。
這些特定的指令位置主要在:
1.方法調用
2.循環跳轉
3.異常跳轉
附:HotSpot對象存活判定和垃圾回收算法的實現(是如何發起內存回收的)
CMS的缺點:
CPU資源敏感:CMS默認回收線程數是(CPU數量+3)/4,CPU數量多還好,數量低了的話,就會佔用較多的CPU資源,影響用戶程序執行速度
無法清除浮動垃圾:可能出現“Concurrent Mode Failure”失敗而導致另一次Full GC(浮動垃圾:由於CMS併發清理階段用戶線程還在運行着,伴隨程序運行自然就還會有新的垃圾不斷產生,這一部分垃圾出現在標記過程之後,CMS無法在當次收集中處理掉它們,只好留待下一次GC時再清理的這一部分垃圾)
空間碎片:基於標記清除算法會產生大量空間碎片,會對大對象的分配帶來麻煩,可能會提前觸發Full GC。CMS會在頂不住快進入Full GC的時候進行內存碎片的合併整理,還會在每次進入Full GC的時候都進行一次碎片整理。
5.G1收集器
(-XX:+UseG1GC 複製+標記-整理算法)
概述:
是jdk1.7以後推出的回收器,解決了CMS垃圾收集時產生的空間碎片,試圖取代CMS回收器
不同於其他的回收器,G1將堆空間劃分成了互相獨立的區塊。每塊區域既有可能屬於老年代、也有可能是新生代,並且每類區域空間可以是不連續的(對比CMS的老年代和新生代都必須是連續的)
這種將老年代區劃分成多塊的理念源於:當併發後臺線程尋找可回收的對象時、有些區塊包含可回收的對象要比其他區塊多很多。雖然在清理這些區塊時G1仍然需要暫停應用線程、但可以用相對較少的時間優先回收包含垃圾最多區塊。
G1相對CMS回收器來說區別在於:
1、G1能夠提供可預測的垃圾回收停頓時間,也可以自己設置相對應的停頓時間
2、G1適用於新生代和老年代,而CMS只適用於老年代
3、CMS使用標記清除算法,G1整體上看是“標記-整理”,局部看是“複製”,這兩種算法都能提供規整的內存空間,從而避免空間碎片的產生
內存結構:
每個Region被標記了E、S、O和H,說明每個Region在運行時都將存儲不同的對象。
其中H是以往算法中沒有的,它代表Humongous,這表示這些Region存儲的是大對象(humongous object,H-obj),當新建對象大小超過Region大小一半時,直接在新的一個或多個連續Region中分配,並標記爲H。
G1將對象從堆的一個或多個區域複製到堆上的單個區域,並且在此過程中壓縮並釋放內存。這種空間分配的動作在多處理器上並行執行,以減少暫停時間並提高吞吐量。因此,每次垃圾收集,G1都會不斷努力減少碎片。
GC模式
G1提供三種垃圾回收模式:young gc、mixed gc 和 full gc,在不同的條件下被觸發。
young gc
發生在年輕代的GC算法,一般對象(除了大對象)都是在eden region中分配內存,當所有eden region被耗盡無法申請內存時,就會觸發一次young gc,這種觸發機制和之前的young gc差不多,執行完一次young gc,活躍對象會被拷貝到survivor region或者晉升到old region中,空閒的region會被放入空閒列表中,等待下次被使用。
mixed gc
當越來越多的對象晉升到老年代old region時,爲了避免堆內存被耗盡,虛擬機會觸發一個混合的垃圾收集器,即mixed gc,該算法並不是一個old gc,除了回收整個young region,還會回收一部分的old region,這裏需要注意:是一部分老年代,而不是全部老年代,可以選擇哪些old region進行收集,從而可以對垃圾回收的耗時時間進行控制。
mixed gc的執行過程有點類似cms,主要分爲以下幾個步驟:
initial mark: 初始標記過程,整個過程STW,標記了從GC Root可達的對象
concurrent marking: 併發標記過程,整個過程gc collector線程與應用線程可以並行執行,標記出GC Root可達對象衍生出去的存活對象,並收集各個Region的存活對象信息
remark: 最終標記過程,整個過程STW,標記出那些在併發標記過程中遺漏的,或者內部引用發生變化的對象
clean up: 垃圾清除過程,如果發現一個Region中沒有存活對象,則把該Region加入到空閒列表中。
full gc
如果對象內存分配速度過快,mixed gc來不及回收,導致老年代被填滿,就會觸發一次full gc,G1的full gc算法就是單線程執行的serial old gc,會導致異常長時間的暫停時間,需要進行不斷的調優,儘可能的避免full gc.
G1大部分內容來自於:
https://www.jianshu.com/p/0f1f5adffdc1
https://docs.oracle.com/javase/8/docs/technotes/guides/vm/gctuning/g1_gc.html