理解JVM(七):垃圾回收器

一些概念

並行(Parallel)

指多條垃圾收集線程並行工做,但此時用戶線程仍然處於等待狀態。java

併發(Concurrent)

指用戶線程與垃圾收集線程同時執行(但不必定是並行的,可能會交替執行),用戶程序在繼續運行,而垃圾收集程序運行於另外一個CPU上。算法

吞吐量

CPU用於運行用戶代碼的時間與CPU總消耗時間的比值,即吞吐量=運行用戶代碼時間/(運行用戶代碼時間+垃圾收集時間)。虛擬機總共運行了100分鐘,其中垃圾收集花掉1分鐘,那吞吐量就是99%。多線程

HotSpot虛擬機的垃圾回收器

Serial

  • 最基本的單線程垃圾收集器。使用一個CPU或一條收集線程去執行垃圾收集工做。
  • 工做時會Stop The World,暫停全部用戶線程,形成卡頓。適合運行在Client模式下的虛擬機。
  • 用做新生代收集器,複製算法。

ParNew

  • Serial收集器的多線程版本,和Serial的惟一區別就是使用了多條線程去垃圾收集。
  • 除了Serial,只有它能夠和CMS搭配使用的收集器。
  • 用做新生代收集器,複製算法。

Parallel Scavenge

  • 用做新生代收集器,複製算法。
  • 關注高吞吐量,能夠高效率地利用CPU時間,儘快完成程序的運算任務,主要適合在後臺運算而不須要太多交互的任務。
  • Parallel Scavenge收集器提供了兩個參數用於精確控制吞吐量,分別是控制最大垃圾收集停頓時間的-XX:MaxGCPauseMillis參數以及直接設置吞吐量大小的-XX:GCTimeRatio參數。

Serial Old

  • Serial收集器的老年代版本,單線程,標記-整理 算法。
  • 通常用於Client模式的虛擬機。
  • 當虛擬機是Server模式時,有2個用途:一種用途是在JDK 1.5以及以前的版本中與Parallel Scavenge收集器搭配使用 ,另外一種用途就是做爲CMS收集器的後備預案,在併發收集發生Concurrent Mode Failure時使用。

Parallel Old

  • Parallel Scavenge收集器的老年代版本,使用多線程和 標記-整理 算法。在JDK 1.6中開始提供。
  • 在注重吞吐量的場合,配合Parallel Scavenge收集器使用。

CMS(Concurrent Mark Sweep)

  • 一種以獲取最短回收停頓時間爲目標的收集器。適合須要與用戶交互的程序,良好的響應速度能提高用戶體驗。
  • 基於 標記—清除 算法。適合做爲老年代收集器。
  • 收集過程分4步:
    • 初始標記(CMS initial mark):只是標記一下GC Roots能直接關聯到的對象,速度很快,會Stop The World
    • 併發標記(CMS concurrent mark):進行GC Roots Tracing(可達性分析)的過程。
    • 從新標記(CMS remark):會Stop The World。爲了修正併發標記期間因用戶程序繼續運做而致使標記產生變更的那一部分對象的標記記錄,這個階段的停頓時間通常比初始標記階段稍長些,但遠比並發標記的時間短。
    • 併發清除(CMS concurrent sweep):回收內存。
  • 耗時最長的併發標記和併發清除過程收集器線程均可以與用戶線程一塊兒工做,因此時併發執行的。
  • 缺點:
    • 併發階段,雖然不會致使用戶線程暫停,但會佔用一部分線程(CPU資源),致使應用變慢,吞吐量下降。默認啓動收集線程數是(CPU數量+3)/4。即當CPU在4個以上時,併發回收時垃圾收集線程很多於25%的CPU資源,而且隨着CPU數量的增長而降低。可是當CPU不足4個(譬如2個)時,CMS對用戶程序的影響就可能變得很大。
    • 沒法清除浮動垃圾。併發清除階段,用戶線程還在運行,還會產生新垃圾。這些垃圾不會在這次GC中被標記,只能等到下次GC被回收。
    • 標記-清除 算法會產生大量不連續內存,致使分配大對象時內存不夠,提早觸發Full GC。

G1

  • 在JDK1.7提供的先進垃圾收集器。
  • 既適合新生代,也適合老年代。
  • 空間整合:使用 標記-整理 算法,不產生碎片空間。
  • 整個Java堆被分爲多個大小相同的的塊(region)。新生代和老年代再也不是物理隔離的,而是一部分region塊組成的集合。
  • 默認把堆平均分紅2048個region,最小1M,最大32M,必須是2的冪次方,能夠經過-XX:G1HeapRegionSize參數指定。region分爲4種:
    • E:eden區,新生代
    • S:survivor區,新生代
    • O:old區,老年代
    • H:humongous區,用來放大對象。當新建對象大小超過region大小一半時,直接在新的一個或多個連續region中分配,並標記爲H
  • 可預測的停頓時間:估算每一個region內的垃圾可回收的空間以及回收須要的時間(經驗值),記錄在一個優先列表中。收集時,優先回收價值最大的region,而不是在整個堆進行全區域回收。這樣提升了回收效率,得名:Garbage-First。
  • G1中有2種GC:
    • young GC:新生代eden區沒有足夠可用空間時觸發。存活的對象移到survivor區或晉升old區。
    • mixed GC:當old區對象不少時,老年代對象空間佔堆總空間的比值達到閾值(-XX:InitiatingHeapOccupancyPercent默認45%)會觸發,它除了回收年輕代,也回收 部分 老年代(回收價值高的部分region)。
  • mixed GC回收步驟:
    • 初始標記(Initial Marking):只是標記一下GC Roots能直接關聯到的對象,而且修改TAMS(Next Top at Mark Start)的值,讓下一階段用戶程序併發運行時,能在正確可用的Region中建立新對象。這階段須要停頓線程(STW),但耗時很短,共用YGC的停頓,因此通常伴隨着YGC發生。
    • 併發標記(Concurrent Marking):進行可達性分析,找出存活對象,耗時長,但可與用戶線程併發執行。
    • 最終標記(Final Marking):修正併發標記階段用戶線程運行致使的變更記錄。會STW,但能夠並行執行,時間不會很長。
    • 篩選回收(Live Data Counting and Evacuation):根據每一個region的回收價值和回收成本排序,根據用戶配置的GC停頓時間開始回收。
  • 當對象分配過快,mixed GC來不及回收,G1會退化,觸發Full GC,它使用單線程的Serial收集器來回收,整個過程STW,要儘可能避免這種狀況。
  • 當內存不多的時候(存活對象佔用大量空間),沒有足夠空間來複制對象,會致使回收失敗。這時會保留被移動過的對象和沒移動的對象,只調整引用。失敗發生後,收集器認爲存活對象被移動了,有足夠空間讓應用程序使用,因而用戶線程繼續工做,等待下一次觸發GC。若是內存不夠,就會觸發Full GC。

參考G1的詳細介紹併發

相關文章
相關標籤/搜索