您好,登錄后才能下訂單哦!
這篇文章主要講解了“JVM垃圾回收器是什么”,文中的講解內容簡單清晰,易于學習與理解,下面請大家跟著小編的思路慢慢深入,一起來研究和學習“JVM垃圾回收器是什么”吧!
并行(Parallel):并行描述的是多條垃圾收集器線程之間的關系,說明同一時間有多條這樣的線程在協同工作,通常默認此時用戶線程是處于等待狀態。
并發(Concurrent):并發描述的是垃圾收集器線程與用戶線程之間的關系,說明同一時間垃圾收集器線程與用戶線程都在運行。由于用戶線程并未被凍結,所以程序仍然能響應服務請求,但由于 垃圾收集器線程占用了一部分系統資源,此時應用程序的處理的吞吐量將受到一定影響。
1. 按線程數分
按照線程數(用于垃圾回收的)可以分為串行垃圾回收器和并行垃圾回收器。
串行垃圾回收器:在同一時間段內只允許有一個cPU用于執行垃圾回收操作,此時工作線程被暫停,直至垃圾收集工作結束。
并行垃圾回收器:可以運用多個CPU同時執行垃圾回收。
2. 按工作模式分
按照按工作模式可以分為并發式垃圾回收器和獨占式垃圾回收器。
并發式垃圾回收器:在同一時間段內只允許有一個cPU用于執行垃圾回收操作,此時工作線程被暫停,直至垃圾收集工作結束。
獨占式垃圾回收器:可以運用多個CPU同時執行垃圾回收。
3. 按碎片處理方式分
按照按工作模式可以分為壓縮式垃圾回收器和非壓縮式垃圾回收器。
壓縮式垃圾回收器會在回收完成后,對存活對象進行壓縮整理,消除回收后的碎片。
串行回收器: serial、serial old
并行回收器: ParNew、Parallel scavenge、Parallel old
并發回收器: CMS、G1
新生代收集器: serial、ParNew、Parallel scavenge;
老年代收集器: Serial old、Parallel old、CMS;
整堆收集器: G1;
Serial收集器是最基礎、歷史最悠久的收集器,曾經(在JDK 1.3.1之前)是HotSpot虛擬機新生代收集器的唯一選擇。Serial收集器是一個單線程工作的收集器,在它進行垃圾收集時,必須暫停其他所有工作線程,直到它收集結束。
Serial Old是Serial收集器的老年代版本。
Serial回收器采用復制算法、串行回收和“Stop The World” 機制執行垃圾回收。
Serial Old回收器標記—壓縮算法、串行回收和“Stop The World” 機制執行垃圾回收。
ParNew收集器實質上是Serial收集器的多線程并行版本,除了同時使用多條線程進行垃圾收集之 外,其余的行為包括Serial收集器可用的所有控制參數、收集算法、Stop The World、對象分配規則、回收策略等都與Serial收集器完全一致。
Parallel Scavenge收集器也是一款新生代收集器,它同樣是基于標記-復制算法實現的收集器,也是 能夠并行收集的多線程收集器。
和ParNew收集器不同,Parallel scavenge收集器的目標則是達到一個可控制的吞吐量,它也被稱為吞吐量優先的垃圾收集器。
吞吐量:處理器用于運行用戶代碼的時間與處理器總消耗時間的比值。
高吞吐量可以最高效率地利用處理器資源,盡快完成程序的運算 任務,主要適合在后臺運算而不需要太多交互的分析任務。
Parallel Old是Parallel Scavenge收集器的老年代版本,支持多線程并發收集,基于標記-整理算法實 現。
CMS(Concurrent Mark Sweep)收集器是一種以獲取最短回收停頓時間為目標的收集器。
CMS收集器是基于標記-清除算法實現的,它的運作可以分為四個步驟,包括:
初始標記
初始標記僅僅只是標記一下GC Roots能直接關聯到的對象,速度很快;
并發標記
并發標記階段就是從GC Roots的直接關聯對象開始遍歷整個對 象圖的過程,這個過程耗時較長但是不需要停頓用戶線程,可以與垃圾收集線程一起并發運行;
重新標記
重 新標記階段則是為了修正并發標記期間,因用戶程序繼續運作而導致標記產生變動的那一部分對象的 標記記錄,這個階段的停頓時間通常會比初始標記階段稍長一 些,但也遠比并發標記階段的時間短;
并發清除
清理刪除掉標記階段判斷的已經死亡的 對象,由于不需要移動存活對象,所以這個階段也是可以與用戶線程同時并發的。
CMS收集器無法處理“浮動垃圾”,有可能出現“Con-current Mode Failure”失敗進而導致另一次完全“Stop The World”的Full GC的產生。
在CMS的并發標記和并發清理階段,用戶線程是還在繼續運行的,程序在運行自然就還會伴隨有新的垃圾對象不斷產生,但這一部分 垃圾對象是出現在標記過程結束以后,CMS無法在當次收集中處理掉它們,只好留待下一次垃圾收集 時再清理掉。這一部分垃圾就稱為“浮動垃圾”。
同樣也是由于在垃圾收集階段用戶線程還需要持續運行,那就還需要預留足夠內存空間提供給用戶線程使用,因此CMS收集器不能像其他收集器那樣等待 到老年代幾乎完全被填滿了再進行收集,必須預留一部分空間供并發收集時的程序運作使用。
CMS是基于“標記-清除”算法實現的收集器,意味著收集結束時會有大量空間碎片產生,空間碎片過多時,將會給大對象分配帶來很大麻煩。
為什么不使用標記—壓縮算法避免碎片?
因為當并發清除時,用標記—壓縮整理內存的話,原來的用戶線程使用的內存就無法使用。要保證用戶線程繼續執行,前提是它運行的資源不受影響。標記—壓縮更適合“Stop The World”場景下使用。
Garbage First開創了收集 器面向局部收集的設計思路和基于Region的內存布局形式,它是一款主要面向服務端應用的垃圾收集器,主要針對配備多核CPU及大容量內存的機器,以極高概率滿足GC停頓時間的同時,還兼具高吞吐量的性能特征。
G1收集器出現之前的所有其他收集器,垃圾收集的目標范圍要么是整個新生代,要么就是整個老年代,再要么就是整個Java堆。而G1可以面向堆內存任何部分來組成回收集(Collection Set)進行回收,衡量標準不再是它屬于哪個分代,而 是哪塊內存中存放的垃圾數量最多,回收收益最大。
1. 并行與并發
并行性:G1在回收期間,可以有多個GC線程同時工作,此時用戶線程Stop The World。
并發性:G1擁有與應用程序交替執行的能力,部分工作可以和應用程序同時執行,因此,一般來說,不會在整個回收階段發生完全阻塞應用程序的情況。
2. 分代收集
G1也仍是遵循分代收集理論設計的,但其堆內存的布局與其他收集器有非常明顯的差異:G1不再堅持固定大小以及固定數量的 分代區域劃分,而是把連續的Java堆劃分為多個大小相等的獨立區域(Region),每一個Region都可以根據需要,扮演新生代的Eden空間、Survivor空間,或者老年代空間。 收集器能夠對扮演不同角色的 Region采用不同的策略去處理,這樣無論是新創建的對象還是已經存活了一段時間、熬過多次收集的 舊對象都能獲取很好的收集效果。
Region中還有一類特殊的Humongous區域,專門用來存儲大對象。G1認為只要大小超過了一個 Region容量一半的對象即可判定為大對象。
3. 空間整合
G1在內存回收時以region作為基本單位,region之間使用復制算法,但整體上可看做是標記—壓縮算法。
4. 可預測的停頓時間模型
G1收集器能建立可預測的停頓時間模型,它將Region作為單次回收的最小單元,即每次收集到的內存空間都是Region大小的整數倍,這樣可以有計劃地避免 在整個Java堆中進行全區域的垃圾收集。
G1收集器去跟蹤各個Region里面的垃圾堆積的“價值”大小,價值即回收所獲得的空間大小以及回收所需時間的經驗值,然后在后臺維護一 個優先級列表,每次根據用戶設定允許的收集停頓時間,優先處理回收價值收益最大的那些Region。
這種使用Region劃分內存空間,以及具有優先級的區域回收方式,保證了G1收集器在有限的時間內獲 取盡可能高的收集效率。
停頓預測模型是以衰減均值為理論基礎來實現的,在垃圾收集過程中,G1收集器會記 錄每個Region的回收耗時、每個Region記憶集里的臟卡數量等各個可測量的步驟花費的成本,并分析得 出平均值、標準偏差、置信度等統計信息。然后通過這些信息預測現在開始回收的話,由 哪些Region組成回收集才可以在不超過期望停頓時間的約束下獲得最高的收益。
使用記憶集避免全堆作為GC Roots掃描,它的每個Region都維護有自己的記憶集,這些記憶集會記錄下別的Region 指向自己的指針,并標記這些指針分別在哪些卡頁的范圍之內。G1的記憶集在存儲結構的本質上是一 種哈希表,Key是別的Region的起始地址,Value是一個集合,里面存儲的元素是卡表的索引號。
初始標記(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的全部空間。這里的操作涉及存活對象的移動,是必須暫停用戶線程,由多條收集器線程并行 完成的。
Shenandoah也是使用基于Region的堆內存布局,同樣 有著用于存放大對象的Humongous Region,默認的回收策略也同樣是優先處理回收價值最大的 Region……但在管理堆內存方面,它與G1至少有三個明顯的不同之處。
G1的回收階段是可以多線程并行的,但卻不能與用戶線程并發,Shenandoah支持并發的整理算法。
默認不使用分代收集的,換言之,不會有 專門的新生代Region或者老年代Region的存在,沒有實現分代,并不是說分代對Shenandoah沒有價值, 這更多是出于性價比的權衡,基于工作量上的考慮而將其放到優先級較低的位置上。
Shenandoah摒棄了在G1中耗費大量內存和計算資源去維護的記憶集,改用名為“連接矩陣”的全局數據結構來記錄跨Region的引用關系,降低了處理跨代指針時的記憶集維護消耗,也降 低了偽共享問題的發生概率。連接矩陣可以簡單理解為一張二維表格,如果Region N有 對象指向Region M,就在表格的N行M列中打上一個標記,在回收時通過這張表格就可以得出哪些Region之間產生了跨代引用。
Shenandoah收集器的工作過程大致可以劃分為以下九個階段:
初始標記:與G1一樣,首先標記與GC Roots直接關聯的對象,這個階段仍 是“Stop The World”的,但停頓時間與堆大小無關,只與GC Roots的數量相關。
并發標記:與G1一樣,遍歷對象圖,標記出全部可達的對象,這個階段 是與用戶線程一起并發的,時間長短取決于堆中存活對象的數量以及對象圖的結構復雜程度。
最終標記:與G1一樣,處理剩余的SATB掃描,并在這個階段統計出回收價值 最高的Region,將這些Region構成一組回收集。最終標記階段也會有一小段短暫的停頓。
并發清理:這個階段用于清理那些整個區域內連一個存活對象都沒有找到 的Region。
并發回收:在這個階段,Shenandoah要把回收集里面的存活對象先復制一份到其他未被使用的Region之 中。并發回收階段運行的時間長短取決于回收集的大小。
初始引用更新:并發回收階段復制對象結束后,還需要把堆中所有指 向舊對象的引用修正到復制后的新地址,這個操作稱為引用更新。引用更新的初始化階段實際上并未 做什么具體的處理,設立這個階段只是為了建立一個線程集合點,確保所有并發回收階段中進行的收 集器線程都已完成分配給它們的對象移動任務而已。初始引用更新時間很短,會產生一個非常短暫的 停頓。
并發引用更新:真正開始進行引用更新操作,這個階段是與用戶 線程一起并發的,時間長短取決于內存中涉及的引用數量的多少。并發引用更新與并發標記不同,它 不再需要沿著對象圖來搜索,只需要按照內存物理地址的順序,線性地搜索出引用類型,把舊值改為 新值即可。
最終引用更新:解決了堆中的引用更新后,還要修正存在于GC Roots 中的引用。這個階段是Shenandoah的最后一次停頓,停頓時間只與GC Roots的數量相關。
并發清理:經過并發回收和引用更新之后,整個回收集中所有的Region已 再無存活對象,這些Region都變成Immediate Garbage Regions了,最后再調用一次并發清理過程來回收 這些Region的內存空間,供以后新對象分配使用。
ZGC和Shenandoah的目標是高度相似的,都希望在盡可能對吞吐量影響不太大的前提下,實現在任意堆內存大小下都可以把垃圾收集的停頓時間限制在十毫秒以內的低延遲。
ZGC收集器是一款基于Region內存布局的,(暫時) 不設分代的,使用了讀屏障、染色指針和內存多重映射等技術來實現可并發的標記-整理算法的,以低 延遲為首要目標的一款垃圾收集器。
ZGC也采用基于Region的堆內存布局,但 與它們不同的是,ZGC的Region具有動態性——動態創建和銷毀,以及動態的區域容量大小。
ZGC的運作過程可分為四個階段:
并發標記(:與G1、Shenandoah一樣,并發標記是遍歷對象圖做可達性分析的 階段,前后也要經過類似于G1、Shenandoah的初始標記、最終標記(盡管ZGC中的名字不叫這些)的 短暫停頓,而且這些停頓階段所做的事情在目標上也是相類似的。與G1、Shenandoah不同的是,ZGC 的標記是在指針上而不是在對象上進行的,標記階段會更新染色指針中的Marked 0、Marked 1標志位。
并發預備重分配:這個階段需要根據特定的查詢條件統計得出 本次收集過程要清理哪些Region,將這些Region組成重分配集。
并發重分配:重分配是ZGC執行過程中的核心階段,這個過程要把重分 配集中的存活對象復制到新的Region上,并為重分配集中的每個Region維護一個轉發表,記錄從舊對象到新對象的轉向關系。
并發重映射:重映射所做的就是修正整個堆中指向重分配集中舊對象的所 有引用。ZGC很巧妙地把并發重映射 階段要做的工作,合并到了下一次垃圾收集循環中的并發標記階段里去完成,反正它們都是要遍歷所 有對象的,這樣合并就節省了一次遍歷對象圖的開銷。一旦所有指針都被修正之后,原來記錄新舊 對象關系的轉發表就可以釋放掉了。
考慮以下三個問題:
如果是數據分析、科學計算類的任務,目標是能盡快算出結果, 那吞吐量就是主要關注點;
如果是SLA應用,那停頓時間直接影響服務質量,嚴重的甚至會導致事務 超時,這樣延遲就是主要關注點;
而如果是客戶端應用或者嵌入式應用,那垃圾收集的內存占用則是 不可忽視的。
硬件規格,要涉及的系統架構是x86-32/64、SPARC還是 ARM/Aarch74;
處理器的數量多少,分配內存的大小;
選擇的操作系統是Linux、Solaris還是Windows 等。
是ZingJDK/Zulu、OracleJDK、Open-JDK、OpenJ9抑 或是其他公司的發行版?該JDK對應了《Java虛擬機規范》的哪個版本?
優先調整堆的大小讓JVM自適應完成。
如果內存小于100M,使用串行收集器
如果是單核、單機程序,并且沒有停頓時間的要求,串行收集器
如果是多CPU、需要高吞吐量、允許停頓時間超過1秒,選擇并行或者JVM自己選擇
如果是多CPU、追求低停頓時間,需快速響應(比如延遲不能超過1秒互聯網應用),使用并發收集器
感謝各位的閱讀,以上就是“JVM垃圾回收器是什么”的內容了,經過本文的學習后,相信大家對JVM垃圾回收器是什么這一問題有了更深刻的體會,具體使用情況還需要大家實踐驗證。這里是億速云,小編將為大家推送更多相關知識點的文章,歡迎關注!
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。