JAVA常用的垃圾回收器
Serial收集器:(序列收集器)
這個收集器是一個單執行緒的收集器,但它的單執行緒的意義並不僅僅說明它只會使用一個CPU或一條收集執行緒去完成垃圾收集工作,更重要的是在它進行垃圾收集時,必須暫停其他所有的工作執行緒(Stop-The-World:將使用者正常工作的執行緒全部暫停掉),直到它收集結束。收集器的執行過程如下圖所示:
上圖中:
新生代採用複製演算法,Stop-The-World
老年代採用標記-整理演算法,Stop-The-World
當它進行GC工作的時候,雖然會造成Stop-The-World,但它存在有存在的原因:正是因為它的簡單而高效(與其他收集器的單執行緒比),對於限定單個CPU的環境來說,沒有執行緒互動的開銷,專心做GC,自然可以獲得最高的單執行緒手機效率。所以Serial收集器對於執行在client模式下是一個很好的選擇(它依然是虛擬機器執行在client模式下的預設新生代收集器)。
ParNew收集器:Serial收集器的多執行緒版本(使用多條執行緒進行GC)
ParNew收集器是Serial收集器的多執行緒版本。
它是執行在server模式下的首選新生代收集器,除了Serial收集器外,目前只有它能與CMS收集器配合工作。CMS收集器是一個被認為具有劃時代意義的併發收集器,因此如果有一個垃圾收集器能和它一起搭配使用讓其更加完美,那這個收集器必然也是一個不可或缺的部分了。收集器的執行過程如下圖所示:
上圖中:
新生代採用複製演算法,Stop-The-World
老年代採用標記-整理演算法,Stop-The-World
ParNew Scanvenge收集器
類似ParNew,但更加關注吞吐量。目標是:達到一個可控制吞吐量的收集器。
停頓時間和吞吐量不可能同時調優。我們一方買希望停頓時間少,另外一方面希望吞吐量高,其實這是矛盾的。因為:在GC的時候,垃圾回收的工作總量是不變的,如果將停頓時間減少,那頻率就會提高;既然頻率提高了,說明就會頻繁的進行GC,那吞吐量就會減少,效能就會降低。
吞吐量:CPU用於使用者程式碼的時間/CPU總消耗時間的比值,即=執行使用者程式碼的時間/(執行使用者程式碼時間+垃圾收集時間)。比如,虛擬機器總共運行了100分鐘,其中垃圾收集花掉1分鐘,那吞吐量就是99%。
G1收集器:
是當今收集器發展的最前言成果之一,知道jdk1.7,sun公司才認為它達到了足夠成熟的商用程度。
優點:
它最大的優點是結合了空間整合,不會產生大量的碎片,也降低了進行gc的頻率。二是可以讓使用者明確指定停頓時間。(可以指定一個最小時間,超過這個時間,就不會進行回收了)它有了這麼高效率的原因之一就是:對垃圾回收進行了劃分優先順序的操作,這種有優先順序的區域回收方式保證了它的高效率。
如果你的應用追求停頓,那G1現在已經可以作為一個可嘗試的選擇;如果你的應用追求吞吐量,那G1並不會為你帶來什麼特別的好處。
注:以上所有的收集器當中,當執行GC時,都會stop the world,但是下面的CMS收集器卻不會這樣。
CMS收集器:(老年代收集器)
CMS收集器(Concurrent Mark Sweep:併發標記清除)是一種以獲取最短回收停頓時間為目標的收集器。適合應用在網際網路站或者B/S系統的伺服器上,這類應用尤其重視伺服器的響應速度,希望系統停頓時間最短。
CMS收集器執行過程:(著重實現了標記的過程)
(1)初始標記
根可以直接關聯到的物件
速度快
(2)併發標記(和使用者執行緒一起)
主要標記過程,標記全部物件
(3)重新標記
由於併發標記時,使用者執行緒依然執行,因此在正式清理前,再做修正
(4)併發清除(和使用者執行緒一起)
基於標記結果,直接清理物件
整個過程如下圖所示:
上圖中,初始標記和重新標記時,需要stop the world。整個過程中耗時最長的是併發標記和併發清除,這兩個過程都可以和使用者執行緒一起工作。
優點:
併發收集,低停頓
缺點:
(1)導致使用者的執行速度降低。
(2)無法處理浮動垃圾。因為它採用的是標記-清除演算法。有可能有些垃圾在標記之後,需要等到下一次GC才會被回收。如果CMS執行期間無法滿足程式需要,那麼就會臨時啟用Serial Old收集器來重新進行老年代的收集。
(3)由於採用的是標記-清除演算法,那麼就會產生大量的碎片。往往會出現老年代還有很大的空間剩餘,但是無法找到足夠大的連續空間來分配當前物件,不得不提前觸發一次full GC。
疑問:既然標記-清除演算法會造成記憶體空間的碎片化,CMS收集器為什麼使用標記清除演算法而不是使用標記整理演算法:
答案:
CMS收集器更加關注停頓,它在做GC的時候是和使用者執行緒一起工作的(併發執行),如果使用標記整理演算法的話,那麼在清理的時候就會去移動可用物件的記憶體空間,那麼應用程式的執行緒就很有可能找不到應用物件在哪裡。