jvm - CMS收集器

CMS是基於標記-清除算法的,收集的時候分爲4個步驟:算法

  1. 初始標記
  2. 併發標記
  3. 從新標記
  4. 併發清除

# 初始標記
初始標記僅僅只是標記一下GC Roots能直接關聯到的對象,因此速度很快。好比下圖,這邊的GC Roots只用了虛擬機棧爲例。兩個虛擬機棧分表建立了對象OBJ_A1和OBJ_B1,他們也各有本身的其餘引用,在這個階段,他只會標記OBJ_A1和OBJ_B1,其餘的引用是不標記的,因此儘管這個階段有STW,可是標記的數量少,時間很快,基本不影響。
image.pngsegmentfault

併發標記

併發標記就是根據初始標記的對象所直接或間接引用的對象進行標記,好比下圖對OBJ_A2,OBJ_AN進行併發標記。這個階段並無STW,因此能夠建立對象,新增新的引用,也會讓某些對象失去引用,好比下圖,OBJ_B1已經變成垃圾了,OBJ_C1是新增存活的對象。這個階段因爲對老年代全部的對象進行跟蹤,因此是很是耗時的。
image.png服務器

從新標記

在併發標記中,咱們看到存活對象OBJ_C1等以及垃圾對象OBJ_B1等是沒有被標記出來的,因此這個階段就是對這些對象進行從新標記。
這個階段也有STW,可是僅僅對併發標記中有變更的對象進行標記,這些數量比較少,因此速度也是很快。
image.png併發

併發清除

這個階段,就是在從新標記後,對垃圾對象的清理,和併發標記同樣,都很耗時,因爲並無STW,因此對程序的運行影響不大。CMS採用的是標記與清除算法。
image.pngjvm

缺點

CMS的4個階段,初始標記和從新標記須要STW,可是時間短,影響不大。併發標記和併發清除不須要STW,雖然耗時,可是併發執行的,影響也不大,看起來CMS很完美,可是他也有一些缺點。spa

CPU

CMS默認啓動的回收線程數是(CPU數量+3)/ 4,也就是當CPU在4個以上時,併發回收時垃圾收集線程很多於25%的CPU資源,而且隨着CPU數量的增長而降低。好比服務器是2核4G,那就須要用(2+3)/4=1個線程去處理併發的標記和併發清除,這時候只剩下1個線程處理其餘事情。線程

浮動垃圾

浮動垃圾的產生,主要是在併發清理階段。從新標記後,CMS垃圾回收器會知道哪些須要清理,在併發清理階段,他就清理從新標記後的垃圾對象,這個階段並無STW,因此有可能產生新的對象,好比下圖的OBJ_N,建立完後,棧幀被回收,引用就沒了,他在這個階段是不能被清除的,只能等下一次垃圾回收的時候,被標記並清除。
若是這個階段進入老年代的對象超過了剩餘空間,就會出現Concurrent Mode Failure失敗,那虛擬機會臨時啓用Serial Old收集器進行老年代的垃圾收集。
能夠用XX:CMSInitiatingOccupancyFraction設置老年代空間被佔用多少百分比觸發CMS回收,JDK1.6後默認92%。
image.png對象

空間碎片

jvm - 垃圾收集算法提過,標記-清除算法會產生空間碎片的,若是連續的內存空間不夠存放即將進入老年代的對象,此時就會觸發Full GC。
爲了不這種狀況,CMS收集器提供了一個-XX:+UseCMSCompactAtFullCollection,默認打開的,當Full GC完成後,他會STW,進行內存整理,把存活的對象緊密的靠在一塊兒,騰出連續空間。
若是每次都要從新內存,那都會STW,因此CMS還提供了-XX:CMSFullGCsBeforeCompaction參數,默認是0,他的意思是進行了多少次Full GC後才整理內存。blog

相關文章
相關標籤/搜索