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