JVM(4)-垃圾回收器

摘要

前一節,咱們講解了內存回收的方法論,從基本的回收對象是否存活引入了:直接引用計數法(對象添加引用計數器)、可達性分析法(引用對象從GC Root出發。經過引用鏈查找),正由於直接引用計數法沒法解決循環引用問題,引入可達性分析法。而後引入垃圾對象回收的算法方法論:最簡單的是「標記-清除法」:使用可達性分析法將內存對象標記爲垃圾對象,而後清除垃圾對象,標記-清除法在對象存活時間比較長的內存區域效率低下:會消耗大量時間標記清除大量內存對象,標記清除法清除垃圾對象的時候會致使不連續的內存空間,引出空間碎片化問題。因此爲了解決上面問題引出了標記-複製算法:將空間分爲兩部分:正在使用的其中一塊空間,當對象標記爲垃圾對象,須要出發GC時候,將存對象一次性移到另外一塊內存,而且使用移動內存指針方式讓另外一塊內存空間連續話,而後gc掉第一塊全部內存,解決了內存碎片化問題,在內存對象存活週期短的區域,只須要移動少許的存活對象到另外一塊區域,效率高,因此適合在堆內存裏面的新生代;對於老年代;咱們須要引出:標記-整理算法:將垃圾對象進行標記,而後gc時候經過指針將內存對象連續化。這一講咱們來研究具體的內存回收實現:垃圾回收器。 算法

咱們主要分析經常使用的虛擬機(HotSpot)的垃圾回收器。
image.png
展現了七種做用於不一樣分代的收集器,若是兩個收集器之間存在連線,就說明它們能夠搭配使用,圖中收集器所處的區域,則表示它是屬於新生代收集器抑或是老年代收集器。瀏覽器

思惟導圖

image.png

內容

咱們從簡單到複雜主要分析5種垃圾回收器:Serial收集器、ParNew收集器、Parallel Scavenge收集器、CMS收集器、G1收集器.多線程

Serial收集器

原理/是什麼:單線程垃圾回收器,進行垃圾回收時候,用戶線程所有中止,直到垃圾回收結束。 併發

圖解:
image.png
單線程工做的收集器,但它的「單線程」的意義並不只僅是說明它只會使用一個處理器或一條收集線程去完成垃圾收集工做,更重要的是強調在它進行垃圾收集時,必須暫停其餘全部工做線程,直到它收集結束。「Stop The World」這個詞語也 許聽起來很酷,但這項工做是由虛擬機在後臺自動發起和自動完成的,在用戶不可知、不可控的狀況 下把用戶的正常工做的線程所有停掉,這對不少應用來講都是不能接受的。
特色:
缺點:「Stop The World」:它進⾏垃圾收集時,必須暫停其餘全部的⼯做線程,直到它收集結束。在⽤戶不可⻅的狀況下把⽤戶正常⼯做的線程所有停掉。(從Serial收集器到Parallel收集器,再到Concurrent Mark Sweep(CMS)和Garbage First(G1)收集器,最終至如今垃圾收集器的最前沿成果Shenandoah和ZGC 等,咱們看到了一個個愈來愈構思精巧,愈來愈優秀,也愈來愈複雜的垃圾收集器不斷涌現,用戶線 程的停頓時間在持續縮短,可是仍然沒有辦法完全消除)
優勢:多⽤於桌⾯應⽤,是客戶端Client模式下的虛擬機。桌⾯應⽤暫用內存⼩,進⾏垃圾回收的時間⽐較短,只要不頻繁發⽣停頓就能夠接受。(由於是單線程的,因此消耗cpu跟內存相對比較小)佈局

ParNew收集器

回顧:
上一節咱們講解了垃圾回收器裏面第一種垃圾回收器Serial。Serial垃圾回收器採用單線程垃圾回收,他的性能是比較差的。爲了解決Serial的性能問題,咱們引入了另外一種垃圾回收器:ParNew垃圾回收器。
原理:ParNew收集器實質上是Serial收集器的多線程並行版本,除了同時使用多條線程進行垃圾收集之 外,其他的行爲包括Serial收集器可用的全部控制參數(例如:-XX:SurvivorRatio、-XX: PretenureSizeThreshold、-XX:HandlePromotionFailure等)、收集算法、Stop The World、對象分配規 則、回收策略等都與Serial收集器徹底一致性能

圖解:
image.png
一、ParNew收集器除了支持多線程並行收集以外,其餘與Serial收集器相比並無太多創新之處,但它 倒是很多運行在服務端模式下的HotSpot虛擬機,尤爲是JDK 7以前的遺留系統中首選的新生代收集 器,其中有一個與功能、性能無關但其實很重要的緣由是:除了Serial收集器外,目前只有它能與CMS 收集器配合工做。
二、CMS做爲老年代的收集器,卻沒法與JDK 1.4.0中已經存在的新生代收集器Parallel Scavenge配合工做[1],因此在JDK 5中使用CMS來收集老年代的時候,新生代只能選擇ParNew或者 Serial收集器中的一個。ParNew收集器是激活CMS後(使用-XX:+UseConcMarkSweepGC選項)的默 認新生代收集器,也可使用-XX:+/-UseParNewGC選項來強制指定或者禁用它。
三、G1是一個面向全堆的收集器,不 再須要其餘新生代收集器的配合工做。因此自JDK 9開始,ParNew加CMS收集器的組合就再也不是官方 推薦的服務端模式下的收集器解決方案了。官方但願它能徹底被G1所取代,甚至還取消了ParNew加 Serial Old以及Serial加CMS這兩組收集器組合的支持(其實本來也不多人這樣使用) 網站

特色:
---一、ParNew 收集器除了多線程收集以外,其餘與 Serial 收集器相⽐並無太多創新之處,但它倒是許多運⾏在 Server 模式下(以前咱們的Serial是運行在client端的)的虛擬機中⾸選的新⽣代收集器,其中有⼀個與性能⽆關但很重要的緣由是,除了 Serial 收集器外,⽬前只有它能與CMS收集器配合⼯做(ParNew通常跟CMS一塊兒來使用;咱們的ParNew通常用來回收新生代,而CMS通常用來回收老年代)。
---二、使⽤-XX: ParallelGCThreads 參數來限制垃圾收集的線程數。(這個設置有一個參照點:你們知道咱們的cpu有一個核數,這個核數表明了咱們cpu同時能處理多少個線程的數量,若是cpu核數是8的話,建議將咱們的ParallelGCThreads參數值設置爲8)
---三、多線程操做存在上下⽂切換的問題,因此建議將-XX: ParallelGCThreads設置成和CPU核數相同,若是設置太多的話就會產⽣上下⽂切換消耗。(因此並非咱們這個ParallelGCThreads參數越大越好、他會有上下文切換的失效)spa

收集器的上下文語境中:併發與並行
併發:描述GC線程跟用戶線程之間關係:GC線程跟用戶線程同時運行。
並行:描述GC線程間關係:多個GC線程同時運行,用戶線程暫停。線程

Parallel Scavenge收集器

回顧:上一節咱們講解了ParNew垃圾回收器,ParNew垃圾回收器是在Serial基礎上實現的一個多線程的擴充。多線程的垃圾回收器除了ParNew以外,還有Parallel Scavenge垃圾回收器。 3d

是什麼:控制的吞吐量的ParNew收集器(也能夠叫作:基於標記-複製算法實現的多線程吞吐量優先的垃圾回收器)

特色: 一、多線程垃圾回收 二、關注吞吐量 三、參數可調。

與其餘垃圾回收器區別: 關注點:其餘垃圾回收線程關注縮短垃圾收集時用戶線程的停頓時間。Parallel Scavenge收集器的目標則是達到一個可控制的吞吐 量(Throughput)

吞吐量: 吞吐量=用戶線程執行時間/用戶線程執行時間+GC線程執行時間

CMS收集器

回顧: 上一節咱們講解了兩個概念,一個是併發一個是並行,而且咱們講解了ParNew跟Parallel Scavenge收集器,他們都是並行的垃圾回收器,當工做線程運行到一半時候會被阻斷運行GC線程,GC垃圾回收以後會再次運行工做線程。除了並行以外,還有一種垃圾回收器他是能夠併發執行的。CMS垃圾收集器。

是什麼?: CMS(Concurrent Mark Sweep)基於標記-清除算法實現的一種以獲取最短回收停頓時間爲目標的收集器。目前很 大一部分的Java應用集中在互聯網網站或者基於瀏覽器的B/S系統的服務端上,這類應用一般都會較爲 關注服務的響應速度,但願系統停頓時間儘量短,以給用戶帶來良好的交互體驗。

圖解4步驟:
image.png
出CMS收集器是基於標記-清除算法實現的整個過程分爲四個步驟,包括: 1)初始標記(CMS initial mark):是標記GC Roots能直接關聯到的對象,速度很快.
2)併發標記(CMS concurrent mark):從GC Roots的直接關聯對象開始遍歷整個對象圖的過程,這個過程耗時較長可是不須要停頓用戶線程,能夠與垃圾收集線程一塊兒併發運行;
3)從新標記(CMS remark):爲了修正併發標記期間,因用戶程序繼續運做而致使標記產生變更的那一部分對象的標記記錄;這個階段的停頓時間一般會比初始標記階段稍長些,但也遠比並發標記階段的時間短;
4)併發清除(CMS concurrent sweep):清理刪除掉標記階段判斷的已經死亡的對象,因爲不須要移動存活對象,因此這個階段也是能夠與用戶線程同時併發的。

初始標記、從新標記這兩個步驟仍然須要「Stop The World」.

因爲在整個過程當中耗時最長的併發標記和併發清除階段中,垃圾收集器線程均可以與用戶線程一 起工做,因此從整體上來講,CMS收集器的內存回收過程是與用戶線程一塊兒併發執行的。能夠比較清楚地看到CMS收集器的運做步驟中併發和須要停頓的階段。

特色:
優勢:併發收集、低停頓。
缺點:
一、對CPU資源⾮常敏感(特別是單核機器-併發會佔用更多資源)
二、⽆法處理浮動垃圾,併發清除時候已經產生了一些垃圾;浮動垃圾:程序在進⾏併發清除階段⽤戶線程所產⽣的新垃圾。
三、標記-清除暫時空間碎⽚。

G1收集器.

回顧:上一節咱們講解CMS垃圾收集器,這一節咱們講解更加高效的垃圾收集器:G1收集器。

是什麼?: G1是⼀款⾯向服務端應⽤的垃圾收集器。是基於標記-整理法;首先他對性能的要求會特別高。

流程步驟:

image.png

·初始標記(Initial Marking): 僅僅只是標記一下GC Roots能直接關聯到的對象,而且修改TAMS 指針的值,讓下一階段用戶線程併發運行時,能正確地在可用的Region中分配新對象。這個階段須要 停頓線程,但耗時很短,並且是借用進行Minor GC的時候同步完成的,因此G1收集器在這個階段實際 並無額外的停頓。
·併發標記(Concurrent Marking): 從GC Root開始對堆中對象進行可達性分析,遞歸掃描整個堆 裏的對象圖,找出要回收的對象,這階段耗時較長,但可與用戶程序併發執行。當對象圖掃描完成以 後,還要從新處理SATB記錄下的在併發時有引用變更的對象。
·最終標記(Final Marking): 對用戶線程作另外一個短暫的暫停,用於處理併發階段結束後仍遺留 下來的最後那少許的SATB記錄。
·篩選回收(Live Data Counting and Evacuation): 負責更新Region的統計數據,對各個Region的回 收價值和成本進行排序,根據用戶所指望的停頓時間來制定回收計劃,能夠自由選擇任意多個Region 構成回收集,而後把決定回收的那一部分Region的存活對象複製到空的Region中,再清理掉整個舊 Region的所有空間。這裏的操做涉及存活對象的移動,是必須暫停用戶線程,由多條收集器線程並行 完成的。從上述階段的描述能夠看出,G1收集器除了併發標記外,其他階段也是要徹底暫停用戶線程的, 換言之,它並不是純粹地追求低延遲,官方給它設定的目標是在延遲可控的狀況下得到儘量高的吞吐 量,因此才能擔當起「全功能收集器」的重任與指望

特色: 跟CMS相比他有什麼特色呢?
G1會將內存塊分紅多個Region.Region就是一個區域。(咱們以前在將CMS、Serial垃圾收集器的時候,咱們都採用了新生代、老年代分區的收集方法,而在G1的時候,對新生代、老年代就不是特別敏感了、他將咱們的每一塊內存分紅了Region,內存區域快會分紅多個Region。咱們垃圾回收時候維護的是Region裏面的信息。)區分Region有什麼用呢?Region裏面有與之對應的RememberSet。當進⾏內存回收時,在 GC 根節點的枚舉範圍中加⼊ Remembered Set 便可保證不對全堆掃描也不會有遺漏 檢查Reference引⽤的對象是否處於不一樣的Region。

優點:
一、空間整合: Region內基於「標記⼀整理」算法實現爲主(避免空間垃圾碎片)和Region之間採⽤複製算法(Region之間存活對象比較少,複製算法效率高)實現的垃圾收集。

二、可預測的停頓:(緣由:由於咱們操做的是region,垃圾回收信息都存放在region裏面,因此他是能夠預測停頓時間的)這是 G1 相對於 CMS 的另⼀⼤優點,下降停頓時間是 G1 和 CMS 共同的關 注點,但 G1 除了追求低停頓外,還能建⽴可預測的停頓時間模型。

三、在 G1 以前的其餘收集器進⾏收集的範圍都是整個新⽣代或者⽼年代,⽽ G1 再也不是這樣。使⽤ G1 收集器時,Java 堆的內存佈局就與其餘收集器有很⼤差異,它將整個 Java 雄劃分爲多個⼤⼩相等的獨⽴區域(Region),雖然還保留有新⽣代和⽼年代的概念,但新⽣代和⽼年
代再也不是物理隔髙的了,它們都是⼀部分 Region(不須要連續)的集合。

四、G1 收集器之因此能建⽴可預測的停頓時間模型,是由於它能夠有計劃地避免在整個 Java 堆

中進⾏全區域的垃圾收集。G1 跟蹤各個 Regions ⾥⾯的垃圾堆積的價值⼤⼩(回收所得到的空間⼤⼩以及回收所需時間的經驗值),在後臺維護⼀個優先列表,每次根據容許的收集時間,優先回收價值最⼤的 Region(這也就是 Garbage- Firsti 名稱的來由)。這種使⽤Region 劃份內存空間以及有優先級的區域回收⽅式,保證了 G1 收集器在有限的時間內能夠獲取儘量⾼。

補充:如今咱們不少公司仍是在使用CMS垃圾回收器,不多會用JDK1.九、JDK.10.因此咱們還不多用G1。

相關文章
相關標籤/搜索