GC垃圾回收之CMS、G1

前瞻:

回收算法:

  • 引用計數法:每個對象都有一個存儲被引用次數的計數器,爲0表示可以被回收,優點快,缺點是2個對象相互引用無法回收。
  • 根搜索法:通過GCroots(根對象)向下查找被應用的對象,回收未被引用的。

GC ROOT對象包括:

  • 虛擬機(JVM)棧中引用對象
  • 方法區中的類靜態屬性引用對象
  • 方法區中常量引用的對象(final 的常量值)
  • 本地方法棧JNI的引用對象

三色標記法

用於標記JVM中的對象狀態。

  • 白:表示對象未被掃描,如果標記結束後還爲白色,則會被回收。
  • 黑:表示對象已被掃描,表示被“gc root”引用,不會被回收。
  • 灰:表示對象正在掃表,表示從上級掃描到了它,但還未掃描它的下級對象,掃描完成會變爲黑。

STW

stop the world,暫停虛擬器,暫停其他用戶線程,只有GC現場運行,程序處於暫停狀態。

 

年輕代回收器

一般使用採用複製收集算法,一個字快。

  • Serial收集器:一個單線程收集器,在進行回收的時候,必須暫停其他所有的工作線程,直到收集結束。缺點:因爲要完全暫停線程,所以用戶體驗不佳。但是由於新生代回收得較快,所以停頓的時間非常少,而且沒有線程切換的開銷,因此也簡單高效。通過-XX:+UseSerialGC參數啓用。
  • ParNew收集器:這個是Serial收集器的多線程版本,適用於多核CPU的設備。但對於單核的設備來說,需要進行線程之間的切換,效率反而沒有單線程的高。通過-XX:ParallelGCThreads參數限制收集的線程數,-XX:+UseParNewGC參數啓用。
  • Parallel Scavenge收集器:該收集器是默認年輕代收集器。他的關注點和其他的收集器不同,其他的關注點是儘可能的縮短Full GC的時間。而該收集器關注的是一個可控的吞吐量。吞吐量=運行代碼的時間/(運行代碼的時間+GC的時間),通過參數-XX:MaxGCPauseMillis設置最大GC的停頓時間和-XX:GCTimeRatio 設置吞吐量的大小。-XX:+UseParallelGC參數啓用。主要適合在後臺運算而不需要太多交互的任務。

CMS

全稱Concurrent Mark and Sweep,併發標記清理回收器,用於對年老代進行回收,目標是儘量減少應用的暫停時間,減少full gc發生的機率,利用和應用程序線程併發的垃圾回收線程來標記清除年老代。CMS並非沒有暫停,而是用兩次短暫停來替代串行標記整理算法的長暫停。

  • 過程
  1. 初始標記(STW initial mark) :需要stop the world,暫停其他用戶線程,CMS單線程從”根對象”開始查找,標記能夠和”根對象”關聯的年老代對象,包括通過年輕代關聯的年老代對象,只標記一級,爲了減少stop時間。
  2. 併發標記(Concurrent marking) :和用戶線程併發處理,在初始標記的對象基礎上,向下標記所有關聯對象。
  3. 併發預清理(Concurrent precleaning): 和用戶線程併發處理,對於在併發標記階段發生變化的對象進行標記,並對它的後續關聯對象進行標記。
  4. 重新標記(STW remark) :需要stop the world,標記哪些從”根對象”開始查找未被標記的對象。因爲之前的併發標記過程中用戶現場可能創建或改變了對象關係,需要重新標記哪些改動。
  5. 併發清理(Concurrent sweeping) :和用戶線程併發處理,清理未被引用的對象。
  6. 併發重置(Concurrent reset):重置CMS的內置數據結構,等待下一次回收。

  • 缺點
  1. 內存空間分散:爲減少回收時間,沒有對內存進行整理,導致內存空間分散,CMS將分散的內存空間記錄在一張表中,JVM分配對象時,根據對象大小在內存空間表中找出可存下的內存空間,如果沒有則出發GC操作。
  2. 需要更多CPU資源:併發需要一直佔用一個CPU,爲提高回收速度,需要更快的CPU。
  3. 需要更大堆空間:爲了在GC時,其他線程還能執行,需要預留一定的空間,所有GC出發一般會設置當內存佔用到一定比例時出發回收。
  • 使用場景
  1. 如果你的應用程序對停頓比較敏感,並且服務器的內存和CPU足夠強大。
  2. 如果在JVM中有相對較多存活時間較長的對象(老年代比較大)會更適合使用CMS。

G1

全稱Garbage First,可用於年輕代和年老代,堆被劃分成 許多個連續的區域(region)。每個區域大小相等,在1M~32M之間。JVM最多支持2000個區域,可推算G1能支持的最大內存爲2000*32M=62.5G。區域(region)的大小在JVM初始化的時候決定,也可以用-XX:G1HeapReginSize設置。

過程

Mixed GC主要可以分爲兩個階段:
1、全局併發標記(global concurrent marking)
全局併發標記又可以進一步細分成下面幾個步驟:

  • 初始標記(initial mark,STW)。它標記了從GC Root開始直接可達的對象。初始標記階段借用young GC的暫停,因而沒有額外的、單獨的暫停階段。
  • 併發標記(Concurrent Marking)。這個階段從GC Root開始對heap中的對象標記,標記線程與應用程序線程並行執行,並且收集各個Region的存活對象信息。過程中還會掃描上文中提到的SATB write barrier所記錄下的引用。
  • 最終標記(Remark,STW)。標記那些在併發標記階段發生變化的對象,將被回收。
  • 清除垃圾(Cleanup,部分STW)。這個階段如果發現完全沒有活對象的region就會將其整體回收到可分配region列表中。 清除空Region。

2、拷貝存活對象(Evacuation)
Evacuation階段是全暫停的。它負責把一部分region裏的活對象拷貝到空region裏去(並行拷貝),然後回收原本的region的空間。Evacuation階段可以自由選擇任意多個region來獨立收集構成收集集合(collection set,簡稱CSet),CSet集合中Region的選定依賴於上文中提到的停頓預測模型,該階段並不evacuate所有有活對象的region,只選擇收益高的少量region來evacuate,這種暫停的開銷就可以(在一定範圍內)可控

G1的垃圾回收過程是和應用程序併發執行的,當Mixed GC的速度趕不上應用程序申請內存的速度的時候,Mixed G1就會降級到Full GC,使用的是Serial GC。Full GC會導致長時間的STW,應該要儘量避免。
導致G1 Full GC的原因可能有兩個:

  1. 沒有足夠的空間存放晉升的對象;
  2. 併發處理過程完成之前空間耗盡。

ZGC

全程Z Garbage Collector,Java 11包含的一個全新垃圾收集器,在G1垃圾回收器的歷年基礎上引入大量新技術,實現快速GC。對於TB級的大堆也能處理,速度是G1的上百倍,還在試用階段,穩定後再做學習。

目標:

  • 停頓時間不超過10ms
  • 停頓時間不隨heap大小或存活對象大小增大而增大
  • 可以處理從幾百兆到幾T的內存大小

使用技術包括:

  • 併發標記:減少stop the world
  • 着色指針:
  • 多重映射:
  • 讀屏障:
  • 重定位:
  • 分區:
  • 壓縮:
發佈了63 篇原創文章 · 獲贊 11 · 訪問量 2萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章