您好,登錄后才能下訂單哦!
本篇內容介紹了“java中的垃圾收集器是什么”的有關知識,在實際案例的操作過程中,不少人都會遇到這樣的困境,接下來就讓小編帶領大家學習一下如何處理這些情況吧!希望大家仔細閱讀,能夠學有所成!
1.經典垃圾收集器
1.1 Serial收集器
1.2 ParNew收集器
1.3 Parallel Scavenge 收集器
1.4 Serial Old 收集器
1.5 Parallel Old 收集器
1.6 CMS 收集器
1.7 Garbage First 收集器
2低延遲垃圾收集器
2.1 Shenandoah收集器
2.2 ZGC收集器
總結
這個收集器是一個單線程工作的收集器,但它的單線程的意義并不僅僅是說明他只會使用一個處理器或一條收集線程去完成垃圾收集工作,更重要對的是強調在它進行垃圾收集時,必須暫停其他所有工作線程,直到它收集結束。
目前已經老無可用,但有著優于其他收集器的地方:簡單而高效
ParNew收集器實質上是Serial收集器的多線程并行版本。因為它是除了Serial收集器之外,目前唯一可以與CMS收集器配合工作的收集器,所以在JDK7之前的遺留系統中被作為首選的新生代收集器
CMS收集器是HotSpot虛擬機中第一款真正意義上支持并發的垃圾收集器,首次實現了讓垃圾收集線程與用戶線程同時工作。但是當選用CMS作為老年代收集器時,新生代收集器只能選擇使用Serial收集器或者ParNew收集器
隨著垃圾收集器技術的不斷改進,G1收集器帶著CMS繼承者和代替者的光環登場。G1收集器是一個面向全堆的收集器,不需要其他新生代收集器的配合工作
Parallel Scavenge收集器也是一款新生代收集器,同樣是基于標記-復制算法實現的收集器,也可以并行收集的多線程收集器。它的特點是它的關注點與其他收集器不同。CMS等收集器的關注點是盡可能地縮短垃圾收集時用戶線程的停頓時間,而Parallel Scavenge收集器的目標則是達到一個可控制的吞吐量。
$$
吞吐量=\frac{運行用戶代碼時間}{運行用戶代碼時間+運行垃圾收集時間}
$$
提供了兩個參數用于精確控制吞吐量:
-XX:MaxGCPauseMillis
參數控制最大垃圾搜集停頓時間,允許的值是一個大于0的毫秒數。收集器將盡力保證內存回收花費的時間不超過用戶的設定值。但是設定過分小的值并不能起到加快回收花費的速度的作用。
-XX:GCTimeRatio
參數直接設置吞吐量大小,允許的值是一個大于0小于100的整數。也就是垃圾收集時間占總時間的比率。相當于吞吐量的倒數。
Parallel Scavenge 收集器還有一個參數:-XX:+UseAdaptiveSizePolicy
這是一個開關參數,當這個參數被激活以后,就不需要人工指定新生代的大小,Eden與Survivor區的比例等等。虛擬機會根據當前系統的運行情況收集性能監控信息,動態調整這些參數。
Serial Old 是 Serial收集器的老年代版本,同樣是一個單線程收集器,使用標記-整理算法。可能有兩種用途:1. 在JDK5以及之前的版本中與Parallel Scavenge收集器搭配使用 2. 作為CMS收集器發生失敗時的后備預案。
Parallel Old 是 Parallel Scavenge收集器的老年代版本,支持多線程并發收集,基于標記-整理算法實現,從JDK6版本開始提供。在注重吞吐量或者處理器資源較為稀缺的場合,都可以優先考慮Parallel Scavenge加Parallel Old收集器這個組合。
CMS收集器是一種以獲取最短回收停頓時間為目標的收集器,基于標記-清除算法實現。整個運作過程分為4步:
步驟名稱 | 行為 |
---|---|
初始標記(CMS initial mark) | 標記一下GC Roots能直接關聯到的對象,需要Stop The World |
并發標記(CMS concurrent mark) | 從GC Roots的直接關聯對象開始遍歷整個對象圖的過程,可以與垃圾收集線程一起并發運行 |
重新標記(CMS remark) | 修正并發標記期間,因用戶程序繼續運作而導致標記產生變動的那一部分對象的標記記錄,需要Stop the World |
并發清楚(CMS concurrent sweep) | 清理刪除掉標記階段判斷的已經死亡的對象,可以與用戶線程同時并發完成 |
CMS收集器存在三個缺點:
1.CMS收集器對處理器資源非常敏感,默認啟動的回收線程數為(處理器核心數量+3)/ 4。在并發階段會因為占用了一部分線程而導致應用程序變慢,降低總吞吐量。
為了緩解這種情況虛擬機提供了“增量式并發收集器”(Incremental Concurrent Mark Sweep/i-CMS)作用是在并發標記、清理的時候讓收集器線程、用戶線程交替運行,盡量減少垃圾收集器線程的獨占資源的時間,這樣整個垃圾收集的過程會更長,但是對用戶程序的影響就會顯得較少一些,直觀感受是速度變慢的時間更多了,但速度下降幅度就沒有那么明顯。效果一般從jdk7開始被聲明為deprecated ,從JDK9發布后被完全廢棄
2.由于CMS收集器無法處理“浮動垃圾”(Floating Garbage),有可能出現"Concurrent Mode Failure" 失敗進而導致另一完全"Stop The World"的Full GC的產生。
可以適當調高參數-XX:CMSInitiatingOccu-pancyFraction的值來提高CMS的觸發百分比,降低內存回收頻率,獲得更好的性能。如果設置的太高將會很容易導致大量的并發失敗產生,性能反而降低
3.由于基于標記-清除算法,可能在收集結束時會有大量的空間碎片產生
通過調節:-XX:+UseCMSCompactAtFullCollection開關參數,默認是開啟的,從jdk9開始廢棄
*** -XX:CMSFullGCsBeforeCompaction 默認值是0,表示每次進入Full GC時都進行碎片整理***
Garbage First 收集器,簡稱 G1收集器,開創了收集器面向局部收集的設計思路和基于Region的內存布局形式。是一款主要面向服務端應用的垃圾收集器。可以面向堆內存的任何部分來組成回收集,衡量的標準不再是它屬于哪個分代,而是哪塊內存中存放的垃圾數量最多,回收收益最大。G1開創的基于Region的堆內存布局是它能夠實現這個目標的關鍵,G1不再堅持固定大小以及固定數量的分代區域劃分,而是把連續的java堆劃分為多個大小相等的獨立區域(Region),每一個Region都可以根據需要,扮演新生代的Eden空間、Survivor空間或者老年代空間。
Region中還有一類特殊的Humongous區域,專門用來存儲大對象。G1認為只要大小超過了Region容量一半的對象就可以判定為大對象。每個Region的大小可以通過參數-XX:G1HeapRegionSize設定,取值范圍為1MB~32MB。
G1收集器之所以可以建立可預測的停頓時間模型,是因為它將Region作為單次回收的最小單元,即每次收集到的內存空間都是Region大小的整數倍,這樣可以有計劃地避免在整個JAVA堆中進行全區域的垃圾收集。更具體的思路是讓G1收集器區跟蹤各個Region里面的垃圾堆積的價值大小,價值即回收所獲得的空間大小以及回收所需要的時間的經驗值,然后在后臺 維護一個優先級列表,每次根據用戶設定允許的收集停頓時間(-XX:MaxGCPauseMillis)優先處理回收價值收益最大的那些Region。
G1的記憶集在存儲結構的本質上是一種哈希表,Key是別的Region的起始地址,Value是一個集合,里面存儲的元素是卡表的索引號。G1收集器通過原始快照(SATB)算法實現了保證其不能打破原本的對象圖結構的目的。
G1收集器運作過程大致分為四個步驟:
步驟 | 行為 |
---|---|
初始標記(Initial Marking) | 標記一下GC Roots能直接關聯到的對象,并且修改TAMS指針的值。這個階段需要停頓線程,而且是借用進行Minor GC的時候同步完成的 |
并發標記(Concurrent Marking) | 從GC Root開始對堆種對象進行可達性分析,遞歸掃描整個堆里的對象圖,找出要回收的對象,可以與用戶程序并發執行。對象圖掃描完成以后,還需要重新處理SATB記錄下的在并發時有引用變動的對象 |
最終標記(Final Marking) | 對用戶線程做另一個短暫的暫停,用于處理并發階段結束后仍遺留下來的最后那少量的SATB記錄 |
篩選回收(Live Data Counting and Evacuation) | 負責更新Region的統計數據,對各個Region的回收價值和成本進行排序,根據用戶所期望的停頓時間來制定回收計劃,可以自由選擇任意多個Region構成回收集,然后把決定回收的那一部分Region的存活對象復制到空的Region中,再清理整個舊Region的全部空間,必須暫停用戶線程 |
Shenandoah收集器是一款只有OpenJDK才會包含的。與G1收集器相比,它們兩者有著相似的堆內存布局,在初始標記、并發標記等許多階段的處理思路上都高度一致。但是在管理內存堆方面,與G1收集器至少有三個方面的明顯的不同之處:
1.支持并發的整理算法:G1的回收階段是可以多線程并行的,但不能與用戶線程并發。Shenandoah后面會講到。
2.Shenandoah收集器默認不使用分代收集。
3.Shenandoah摒棄了在G1中耗費大量內存和計算資源去維護的記憶集,改名為“連接矩陣”(Connection Matrix)的全局數據結構來記錄跨Region的引用關系。降低了處理跨代指針的記憶集維護消耗,也降低了偽共享問題發生的概率
Shenandoah收集器大致工作流程可以分為9個階段:
步驟名稱 | 動作 |
---|---|
初始標記(Initial Marking) | 標記與GC Roots直接關聯的對象,這個階段是Stop The World的,停頓時長與堆大小無關,與GC Roots的數量相關。 |
并發標記(Concurrent Marking) | 遍歷對象圖,標記出全部可達的對象,這個階段與用戶線程一起并發的,時間長短取決于堆中存活對象的數量以及對象圖的結構復雜程度。 |
最終標記(Final Marking) | 處理剩余的SATB掃描,在這個階段統計出回收價值最高的Region,將這些Region構成一組回收集,最終標記階段也會有一小段短暫的停頓。 |
并發清理(Concurrent Cleanup) | 清理那些整個區域內連一個存活對象都沒有找到的Region(這類Region被稱為Immediate Garbage Region)。 |
并發回收(Concurrent Evacuation) | 核心差異!Shenandoah要把回收集里面的存活對象先復制一份到其他未被使用的Region之中。Shenandoah會通過讀屏障和被成稱為"Brooks Points"的轉發指針來解決在復制對象時遇到的困難。時間長短取決于回收集的大小。 |
初始引用更新(Initial Update Reference) | 把堆中所有指向舊對象的引用修正到復制后的新地址,這個操作稱為引用更新。在此階段,只是建立了一個線程集合點,確保所有的并發回收階段中進行的收集器線程都已完成分配給它們的對象移動任務而已。時間會很短,有一個十分短暫的停頓。 |
并發引用更新(Comcurrent Update Reference) | 真正開始進行引用更新操作,與用戶線程一起并發的,時間長短取決于內存中涉及的引用數量的多少。只需要按照內存物理地址的順序,線性搜索出引用類型,把舊值改為新值即可。 |
最終引用更新(Final Update Reference) | 解決了堆中的引用更新后,還要修正存在于GC Roots中的引用。這個階段是最后一次停頓,時間與GC Roots的數量有關。 |
并發清理(Concurrent Cleanup) | 此時整個回收集中所有的Region已再無存活對象,都變成了Immediate Garbage Regions了,最后調用一次并發清理過程來回收這些Region的內存空間,供以后新對象分配使用。 |
Brooks Points:Brooks是一個人的名字,它提出使用了轉發指針(Forwarding Pointer)的技術來實現對象移動與用戶程序并發的一種解決方案。不需要用到內存保護陷阱,而是在原有對象布局結構的最前面統一增加一個新的引用字段,在正常不處于并發移動的情況下,該引用指向對象自己。實際上Shenandoah收集器是通過比較并交換(Compare And Swap, CAS)操作來保證并發時對象的訪問正確性的。
JDK13中Shenandoah的內存屏障模型改進為基于引用訪問屏障(Load Reference Barrier)的實現,所謂“引用訪問屏障”是指內存屏障只攔截對象中數據類型為引用類型的讀寫操作,而不去管原生數據類型等其他非引用字段的讀寫。這能省去大量對原生類型、對象比較、對象加鎖等場景中設置內存屏障所帶來的消耗。
ZGC收集器是一款基于Region內存布局的,暫時不設分代的,使用了讀屏障、染色指針和內存多重映射等技術來實現可并發的標記-整理算法的,以低延遲為首要目標的一款垃圾收集器。
ZGC的Region具有動態性-動態創建和銷毀,以及動態的區域容量大小。
染色指針(Colored Pointer):一種直接將少量額外的信息存儲在指針上的技術。盡管在linux下64位指針的高18位不能用來尋址,但是剩余的46位所能支持的64TB內存仍然能夠充分滿足需要。鑒于此,將其高4位提取出來存儲四個標記信息。通過這些標志位,虛擬機可以直接從指針中看到其引用對象的三色標記狀態、是否進入了重分配集、是否只能通過finalize( )方法才能被訪問到。也使得ZGC能夠管理的內存不可以超過4TB。使用染色指針的三大優勢:
1.可以使得一旦某個Region的存活對象被移走之后,這個Region立即就能被釋放和重用掉,不必等待整個堆中所有指向該Region的引用都被修正后才能清理。
2.可以大幅度減少在垃圾收集過程中的內存屏障的使用數量。到目前為止,ZGC都未使用寫屏障,只使用了讀屏障。
3.可以作為一種可擴展的存儲結構用來記錄更多與對象標記、重定位過程相關的數據,以便日后進一步提高性能。
Linux/x86-64平臺上的ZGC使用了多重映射將多個不同的虛擬內存地址映射到同一個物理內存地址上,意味著ZGC在虛擬內存中看到的地址空間要比實際的堆內存容量來得更大。把染色指針中的標志位看作是地址的分段符,只要將這些不同的地址段都映射到同一個物理內存空間,經過多重映射轉換后,就可以使用染色指針正常進行尋址了。
ZGC的運作過程(省略部分與之前介紹的G1和Shenandoah相同的小階段部分):
步驟 | 動作 |
---|---|
并發標記(Concurrent Mark) | 遍歷對象圖做可達性分析的階段,前后也要經過初始標記、最終標記的短暫停頓。ZGC的標記是在指針上而不是在對象上進行的,標記階段會更新染色指針中的Marked 0、Marked 1 標志位。 |
并發預備重分配(Concurrent Prepare for Relocate) | 根據特定的查詢條件統計得出本次收集過程要清理那些Region,將這些Region組成重分配集。與G1收集器的回收集還是有區別的,ZGC的重分配集只是決定了里面的存活對象會被重新分配復制到其他的Region中,里面的Region會被釋放,而并不能說回收行為就只是針對這個集合里面的Region進行,因為標記過程是針對全堆的。 |
并發重分配(Concurrent Reolcate) | 核心階段!把重分配集中的存活對象復制到新的Region上,并未重分配集中的每個Region維護一個轉發表,記錄從舊對象到新對象的轉向關系。 |
并發重映射(Concurrent Remap) | 修正整個堆中指向重分配集中舊對象的所有引用。 |
“java中的垃圾收集器是什么”的內容就介紹到這里了,感謝大家的閱讀。如果想了解更多行業相關的知識可以關注億速云網站,小編將為大家輸出更多高質量的實用文章!
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。