java虛擬機(三)垃圾收集器

此文章介紹垃圾收集器的種類,及各個收集的優缺點和相應的垃圾收集算法的應用

垃圾收集器(7種)

  • Serisl收集器
  • ParNew收集器
  • Parallel Scavenge 收集器
  • Serial Old 收集器
  • Parallel Old 收集器
  • CMS 收集器
  • G1垃圾回收器

Serisl收集器

  • Serisl收集器是最基本,發展歷史最悠久的收集器,曾經在JDK1.3.1之前是虛擬機新生代收集的唯一選擇
  • Serisl收集器是一個單線程的收集器,只會使用一個CPU或一條收集線程曲完成垃圾收集
  • 在進行垃圾收集時,必須暫停其他所有的工作線程,直到收集結束
虛擬機運行在Client模式下的默認新生代收集器
  • 與其他收集器的單線程比簡單而高效
  • 對於限定單個CPU的環境來說,Serial收集器由於沒有線程交互的開銷,專心做垃圾收集自然可以獲得最高的單線程收集效率
  • 在用戶的桌面應用場景中,分配給虛擬機管理的內存一般來說不會很大,收集幾十兆甚至一兩百兆的新生代(僅僅是新生代使用的內存,桌面應用基本上不會再大了),停頓時間完全可以控制在幾十毫秒最多一百多毫秒以內,只要不是頻繁發生,這點停頓是可以接受的

ParNew收集器

  • ParNew收集器其實就是Serial收集器的多線程版本
  • 它也是運行在年輕代中,在新生代中採用的是多線程模式進行垃圾收集同時也需要暫停用戶線程直到垃圾收集完畢。
  • ParNew收集器在單個CPU的環境中絕對不會有比Serial收集器更好的效果,甚至由於存在線程交互的開銷,該收集器在通過超線程技術實現的兩個CPU的環境中都不能百分之百的保證可以超越Serial收集器
  • 這種模式和Serial相比,CPU數量越多的情況下優勢更加明,它默認開啓的收集線程數與CPU的數量相同,在CPU非常多的環境下,可以使用-XX:ParallelGCThreads參數來限制垃圾收集的線程數
是許多運行在Server模式下的虛擬機中首選的新生代收集器
  • 一個與性能無關但很重要的原因:除了Serial收集器外,目前只有它能與CMS收集器配合工作
  • 這種模式和Serial相比,CPU數量越多的情況下優勢更加明

Parallel Scavenge 收集器

  • Parallel Scavenge 收集器是新生代收集器
  • 是使用複製算法的收集器
  • 是並行的多線程收集器
  • Parallel Scavenge 收集器關注的點與其它收集器不同,CMS等收集器關注的點是儘可能的縮短垃圾收集時用戶線程的停頓時間,而Parallel Scavenge 收集器的目標是達到一個可控制的吞吐量
吞吐量:吞吐量就是CPU用於運行用戶代碼的時間於CPU總消耗時間的比值,即吞吐量 = 運行用戶代碼時間/(運行用戶代碼時間+垃圾收集時間),虛擬機總共運行了100分鐘,其中垃圾收集花掉1分鐘,那麼吞吐量就是99%

適用場景

停頓時間越短就越適合需要與用戶交互的程序,良好的響應速度能提升用戶體驗
高吞吐量則可以高效率的利用CPU時間,儘快完成程序的運算任務,主要適合在後臺運算而不需要太多交互的任務

Serial Old 收集器

  • Serial Old 是Serial收集器的老年代版本,它同樣時一個單線程收集器
  • 使用"標記-清除"算法
  • 這個收集器的主要意義也是在於給Client模式下的虛擬機使用

Parallel Old 收集器

  • Parallel Old 是Parallel Scavenge 收集器的老年代版本
  • 使用多線程和"標記-整理"算法
  • Parallel Old 收集器出現後,"吞吐量優先"收集器可以組合出現,在注重吞吐量以及CPU資源敏感的場合,都可以優先考慮Parallel Scavenge 加 Parallel Old收集器
CMS(Concurrent Mark Sweep)收集器
  • 收集器是一種以獲取最短回收停頓時間爲目標的收集器
  • 從名字(包含“Mark Sweep”)上就可以看出CMS收集器是基於“標記-清除”算法實現的

CMS收集器整個過程分爲4個步驟

  • 初始標記 (CMS initial mark)
  • 併發標記 (CMS concurrent mark)
  • 重新標記 (CMS remark)
  • 併發清除 (CMS concurrent sweep)
細節
  • 其中初始標記、重新標記這兩個步驟仍然需要"Stop The Word"
  • 初始標記僅僅只是標記一下GC Roots 能直接關聯到的對象,速度很快,
  • 併發標記階段就是進行GC Roots Tracing的過程
  • 而重新標記階段這是爲了修正併發標記期間,因用戶程序繼續運作而導致標記產生變化的一部分對象的標記記錄,這個階段的停頓時間一般會比初始標記階段稍長一些,但遠比並發標記的時間短
  • 由於這個過程中耗時最長的併發標記和併發清除過程中,收集器線程都可以與用戶線程一起工作
  • CMS收集器的內存回收過程是與用戶線程一起併發的執行的
CMS收集器優點
  • 併發收集,低停頓
CMS收集器缺點
  • CMS收集器對CPU資源非常敏感,其實,面向併發設計的程序都對CPU資源比較敏感。
  • 在併發階段,它雖然不會導致用戶線程停頓,但是會因爲佔用了一部分線程(或者說CPU資源)而導致應用程序變慢,總吞吐量會降低
  • 當CPU不足4個時(譬如2個),CMS對用戶程序的影響就可能變得很大,如果本來CPU負載較大,還要分出一半的運算能力曲執行收集器線程,就可能導致用戶程序的執行速度忽然降低了50%,讓人無法接受
CMS收集器無法處理浮動垃圾
  • 由於CMS併發清理階段用戶線程還在運行着,伴隨程序的運行自然還會有新的垃圾產生,這一部分出現在標記過程之後,CMS無法在本次收集中處理掉他們,只好留待下次GC時再將其清理掉,這一部分垃圾就稱爲"浮動垃圾"
  • 由於在垃圾收集階段用戶線程還需要運行,那也就還需要預留有足夠的內存空間給用戶線程使用,因此CMS收集器不能像其它收集器那樣等到老年代幾乎完全被填滿了在進行收集,需要預留一部分空間提供給併發收集時的程序運行使用
CMS是一款基於""標記-清除"算法實現的收集器,收集結束後會產生大量的內存碎片,
  • 空間碎片過多時,往往會出現老年代還有很大空間剩餘,但是無法找到足夠大的連續空間來分配當前對象,不得不提前觸發以此Full GC
  • 爲了解決這個問題,CMS收集器提供了一個-XX:+UseCMSCompactATFullCollection開關參數(默認就是開啓的),用於在CMS收集器頂不住要進行Full GC 時開啓內存碎片的合併整理過程,內存整理的過程是無法併發的,空間碎片問題沒有了,但停頓時間不得不變長
  • 還提供了另外一個參數-XX:CMSFullGCsBeforeCompaction,這個參數是用於設置執行多少次不壓縮的Full GC後,跟着來一次帶壓縮的(默認值爲0,表示每次進入Full GC時都進行碎片整理)

G1垃圾回收器

Region

  • G1裏面的Region的概念不同於傳統的垃圾回收算法中的分區的概念。
  • G1默認把堆內存分爲1024個分區,後續垃圾收集的單位都是以Region爲單位的。
  • Region是實現G1算法的基礎,每個Region的大小相等,通過-XX:G1HeapRegionSize參數可以設置Region的大小

Remembered Set:

  • RSet全稱是Remember Set,每個Region中都有一個RSet,記錄的是其他Region中的對象引用本Region對象的關係(誰引用了我的對象)
  • 記錄集Remembered Sets簡稱RSet,用於記錄對象在不同分區之間的引用關係,目的是爲了加速垃圾回收的速度,主要是加速標記階段
  • G1爲了避免整堆掃描,爲每個分區記錄了一個RSet,記錄引用分區內對象的card索引。這樣標記時,僅僅需要掃描對應分區的對應card中的對象是否可達即可,極大的提升了GC效率
  • G1裏面還有另外一種數據結構就Collection Set(CSet),CSet記錄的是GC要收集的Region的集合,CSet裏的Region可以是任意代的。在GC的時候,對於old->young和old->old的跨代對象引用,只要掃描對應的CSet中的RSet即可

是一款面向服務端應用的垃圾收集器,與CMS相比,如下特點

1. 並行與併發

G1能充分利用多CPU、多核環境下的硬件優勢,使用多個CPU(CPU或者CPU核心)來縮短Stop-The-World 停頓的時間,部分其它收集器原本需要停頓java線程執行的GC動作,G1收集器仍然可以通過併發的方式讓java程序繼續執行

2.分代收集

與其他收集器一樣,非帶概念在G1中依然得以保留,雖然G1可以不需要其它收集器配合就能獨立管理整個GC堆,但它能夠採用不同的方式去處理新創建的對象和已經存活了一段時間,熬過多次GC的舊對象一夥去更好的收集效果

3.空間整合

  • 與CMS的"標記-清除"算法不同,G1從整體來看是基於"標記-整理"算法實現的收集器
  • 從局部(兩個Regon之間)上來看是基於"複製"算法實現的,但是無論如何,這兩個算法都意味着G1運作期間不會產生內存空間碎片,收集後能提供規整的可用內存
  • 這種特性有利於程序長時間運行,分配大對象時不會因爲無法找到連續內存空間而提前觸發下一次GC

4.可預測的停頓

這是G1相對CMS的另一大優勢,降低停頓時間是G1和CMS共同的關注點,但是G1除了追求低停頓外,還能建立可預測的停頓時間模型,通過停頓預測模型來根據用戶配置的停頓時間來選擇CSet的大小,從而達到用戶期待的應用程序暫停時間

關於停頓時間的設置並不是越短越好。
  • 設置的時間越短意味着每次收集的CSet越小,導致垃圾逐步積累變多,最終不得不退化成Serial GC;
  • 停頓時間設置的過長,那麼會導致每次都會產生長時間的停頓,影響了程序對外的響應時間
  • 通過-XX:MaxGCPauseMillis參數來設置

不計算維護Remembered Set 的操作,G1收集器的運作大致可以劃分爲以下幾個步驟

  • 初始化標記
  • 併發標記
  • 最終標記
  • 篩選回收
詳細
  • 初始化標記階段僅僅只是標記一下GC Roots能直接關聯到的對象,並且修改TAMS(Next Top at Mark Start)的值,讓下一階段用戶程序併發運行時,能在正確可用的Region中創建新對象,這階段需要停頓線程,但耗時很短
  • 併發標記階段是從GC Root 開始對堆中對象進行可達性分析,找出存活的對象,這階段耗時較長,但可與用戶程序併發執行
  • 最終標記階段需要把Remembered Set Logs的數據合併到Remembered Set 中,這階段需要停頓線程,但是可並行執行
  • 篩選回收階段首先對各個Region的回收價值和成本進行排序,根據用戶所期望的GC停頓時間來制定回收計劃,這個階段可以坐到與用戶程序一起併發執行,但是因爲只回收一部分Region,時間是用戶可控制的,而且停頓用戶線程將大幅度提高收集效率

下一篇java虛擬機(四)垃圾回收分代內存分配策略

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章