API進(jìn)階之路】人少錢少需求多的新項目,該怎么帶?">【API進(jìn)階之路】人少錢少需求多的新項目,該怎么帶?
970
2025-04-01
在前面,我們已經(jīng)了解了JVM的分代收集,知道JVM垃圾收集在新生代主要采用標(biāo)記-復(fù)制算法,在老年代主要采用標(biāo)記-清除和標(biāo)記-整理算法。接下來,我們看一看JDK默認(rèn)虛擬機(jī)HotSpot的一些垃圾收集器的實(shí)現(xiàn)。
1、常見垃圾回收器
首先來看一下JDK 11之前全部可用的垃圾收集器。
圖中列出了七種垃圾收集器,連線表示可以配合使用,所在區(qū)域表示它是屬于新生代收集器或是老年代收集器。
這里還標(biāo)出了垃圾收集器采用的收集算法,G1收集器比較特殊,整體采用標(biāo)記-整理算法,局部采用標(biāo)記-復(fù)制算法,后面再細(xì)講。
1.1、Serial收集器
Serial收集器是最基礎(chǔ)、歷史最悠久的收集器。
如同它的名字(串行),它是一個單線程工作的收集器,使用一個處理器或一條收集線程去完成垃圾收集工作。并且進(jìn)行垃圾收集時,必須暫停其他所有工作線程,直到垃圾收集結(jié)束——這就是所謂的“Stop The World”。
Serial/Serial Old收集器的運(yùn)行過程如圖:
1.2、ParNew收集器
ParNew收集器實(shí)質(zhì)上是Serial收集器的多線程并行版本,使用多條線程進(jìn)行垃圾收集。
ParNew收集器的工作過程如圖所示:
這里值得一提的是Par是Parallel(并行)的縮寫,但需要注意的是,這個并行(Parallel)僅僅是描述同一時間多條GC線程協(xié)同工作,而不是GC線程和用戶線程同時運(yùn)行。ParNew垃圾收集也是需要Stop The World的。
1.3、Parallel Scavenge收集器
Parallel Scavenge收集器是一款新生代收集器,基于標(biāo)記-復(fù)制算法實(shí)現(xiàn),也能夠并行收集。和ParNew有些類似,但Parallel Scavenge主要關(guān)注的是垃圾收集的吞吐量。
所謂吞吐量指的是運(yùn)行用戶代碼的時間與處理器總消耗時間的比值。這個比例越高,證明垃圾收集占整個程序運(yùn)行的比例越小。
Parallel Scavenge收集器提供了兩個參數(shù)用于精確控制吞吐量:
-XX:MaxGCPauseMillis,最大垃圾回收停頓時間。這個參數(shù)的原理是空間換時間,收集器會控制新生代的區(qū)域大小,從而盡可能保證回收少于這個最大停頓時間。簡單的說就是回收的區(qū)域越小,那么耗費(fèi)的時間也越小。
所以這個參數(shù)并不是設(shè)置得越小越好。設(shè)太小的話,新生代空間會太小,從而更頻繁的觸發(fā)GC。
-XX:GCTimeRatio,垃圾收集時間與總時間占比。這個是吞吐量的倒數(shù),原理和MaxGCPauseMillis相同。
由于與吞吐量關(guān)系密切,Parallel Scavenge收集器也經(jīng)常被稱作“吞吐量優(yōu)先收集器”。
1.4、Serial Old收集器
Serial Old是Serial收集器的老年代版本,它同樣是一個單線程收集器,使用標(biāo)記-整理算法。
Serial Old收集器的工作過程如圖:
1.5、Parallel Old收集器
Parallel Old是Parallel Scavenge收集器的老年代版本,支持多線程并發(fā)收集,基于標(biāo)記-整理算法實(shí)現(xiàn)。
1.6、CMS收集器
CMS(Concurrent Mark Sweep)收集器是一種以獲取最短回收停頓時間為目標(biāo)的收集器,同樣是老年代的收集齊,采用標(biāo)記-清除算法。
CMS收集齊的垃圾收集分為四步:
初始標(biāo)記(CMS initial mark):單線程運(yùn)行,需要Stop The World,標(biāo)記GC Roots能直達(dá)的對象。
并發(fā)標(biāo)記((CMS concurrent mark):無停頓,和用戶線程同時運(yùn)行,從GC Roots直達(dá)對象開始遍歷整個對象圖。
重新標(biāo)記(CMS remark):多線程運(yùn)行,需要Stop The World,標(biāo)記并發(fā)標(biāo)記階段產(chǎn)生對象。
并發(fā)清除(CMS concurrent sweep):無停頓,和用戶線程同時運(yùn)行,清理掉標(biāo)記階段標(biāo)記的死亡的對象。
涉及到了多次標(biāo)記的過程,這里插入一點(diǎn)三色抽象的知識。三色抽象用來描述對象在垃圾收集過程中的狀態(tài)。
通常白色代表對象未被掃描到,灰色表示對象被掃描到但未被處理,黑色表示對象及其后代已被處理。在CMS的標(biāo)記和清除過程中就用到了這種抽象,詳細(xì)的可以查看參考【5】。
Concurrent Mark Sweep收集器運(yùn)行示意圖如下:
優(yōu)點(diǎn):CMS最主要的優(yōu)點(diǎn)在名字上已經(jīng)體現(xiàn)出來——并發(fā)收集、低停頓。
缺點(diǎn):CMS同樣有三個明顯的缺點(diǎn)。
Mark Sweep算法會導(dǎo)致內(nèi)存碎片比較多
CMS的并發(fā)能力比較依賴于CPU資源,并發(fā)回收時垃圾收集線程可能會搶占用戶線程的資源,導(dǎo)致用戶程序性能下降。
并發(fā)清除階段,用戶線程依然在運(yùn)行,會產(chǎn)生所謂的理“浮動垃圾”(Floating Garbage),本次垃圾收集無法處理浮動垃圾,必須到下一次垃圾收集才能處理。如果浮動垃圾太多,會觸發(fā)新的垃圾回收,導(dǎo)致性能降低。
1.7、Garbage First收集器
Garbage First(簡稱G1)收集器是垃圾收集器的一個顛覆性的產(chǎn)物,它開創(chuàng)了局部收集的設(shè)計思路和基于Region的內(nèi)存布局形式。
雖然G1也仍是遵循分代收集理論設(shè)計的,但其堆內(nèi)存的布局與其他收集器有非常明顯的差異。以前的收集器分代是劃分新生代、老年代、持久代等。
G1把連續(xù)的Java堆劃分為多個大小相等的獨(dú)立區(qū)域(Region),每一個Region都可以根據(jù)需要,扮演新生代的Eden空間、Survivor空間,或者老年代空間。收集器能夠?qū)Π缪莶煌巧腞egion采用不同的策略去處理。
這樣就避免了收集整個堆,而是按照若干個Region集進(jìn)行收集,同時維護(hù)一個優(yōu)先級列表,跟蹤各個Region回收的“價值,優(yōu)先收集價值高的Region。
G1收集器的運(yùn)行過程大致可劃分為以下四個步驟:
初始標(biāo)記(initial mark),標(biāo)記了從GC Root開始直接關(guān)聯(lián)可達(dá)的對象。STW(Stop the World)執(zhí)行。
并發(fā)標(biāo)記(concurrent marking),和用戶線程并發(fā)執(zhí)行,從GC Root開始對堆中對象進(jìn)行可達(dá)性分析,遞歸掃描整個堆里的對象圖,找出要回收的對象、
最終標(biāo)記(Remark),STW,標(biāo)記再并發(fā)標(biāo)記過程中產(chǎn)生的垃圾。
篩選回收(Live Data Counting And Evacuation),制定回收計劃,選擇多個Region 構(gòu)成回收集,把回收集中Region的存活對象復(fù)制到空的Region中,再清理掉整個舊 Region的全部空間。需要STW。
相比CMS,G1的優(yōu)點(diǎn)有很多,可以指定最大停頓時間、分Region的內(nèi)存布局、按收益動態(tài)確定回收集。
只從內(nèi)存的角度來看,與CMS的“標(biāo)記-清除”算法不同,G1從整體來看是基于“標(biāo)記-整理”算法實(shí)現(xiàn)的收集器,但從局部(兩個Region 之間)上看又是基于“標(biāo)記-復(fù)制”算法實(shí)現(xiàn),無論如何,這兩種算法都意味著G1運(yùn)作期間不會產(chǎn)生內(nèi)存空間碎片,垃圾收集完成之后能提供規(guī)整的可用內(nèi)存。
2、前沿垃圾回收器
2.1、ZGC收集器
在JDK 11當(dāng)中,加入了實(shí)驗性質(zhì)的ZGC。它的回收耗時平均不到2毫秒。它是一款低停頓高并發(fā)的收集器。
與CMS中的ParNew和G1類似,ZGC也采用標(biāo)記-復(fù)制算法,不過ZGC對該算法做了重大改進(jìn):ZGC在標(biāo)記、轉(zhuǎn)移和重定位階段幾乎都是并發(fā)的,這是ZGC實(shí)現(xiàn)停頓時間小于10ms目標(biāo)的最關(guān)鍵原因。
ZGC雖然在JDK 11還處于實(shí)驗階段,但由于算法與思想是一個非常大的提升,未來前景相信還是很廣闊的。
3、垃圾收集器選擇
3.1、收集器選擇權(quán)衡
垃圾收集器的選擇需要權(quán)衡的點(diǎn)還是比較多的——例如運(yùn)行應(yīng)用的基礎(chǔ)設(shè)施如何?使用JDK的發(fā)行商是什么?等等……
這里簡單地列一下上面提到的一些收集器的適用場景:
Serial :如果應(yīng)用程序有一個很小的內(nèi)存空間(大約100 MB)亦或它在沒有停頓時間要求的單線程處理器上運(yùn)行。
Parallel:如果優(yōu)先考慮應(yīng)用程序的峰值性能,并且沒有時間要求要求,或者可以接受1秒或更長的停頓時間。
CMS/G1:如果響應(yīng)時間比吞吐量優(yōu)先級高,亦或垃圾收集暫停必須保持在大約1秒以內(nèi)。
ZGC:如果響應(yīng)時間是高優(yōu)先級的,亦或堆空間比較大。
3.1、設(shè)置垃圾收集器
設(shè)置垃圾收集器(組合)的參數(shù)如下:
參考:
【1】:周志朋編著《深入理解Java虛擬機(jī):JVM高級特性與最佳實(shí)踐》
【2】:《垃圾回收算法手冊 自動內(nèi)存管理的藝術(shù)》
【3】:Garbage Collection in Java – What is GC and How it Works in the JVM
【4】:Java Hotspot G1 GC的一些關(guān)鍵技術(shù)
【5】:GC Algorithms: Implementations
【6】:新一代垃圾回收器ZGC的探索與實(shí)踐
JVM 任務(wù)調(diào)度
版權(quán)聲明:本文內(nèi)容由網(wǎng)絡(luò)用戶投稿,版權(quán)歸原作者所有,本站不擁有其著作權(quán),亦不承擔(dān)相應(yīng)法律責(zé)任。如果您發(fā)現(xiàn)本站中有涉嫌抄襲或描述失實(shí)的內(nèi)容,請聯(lián)系我們jiasou666@gmail.com 處理,核實(shí)后本網(wǎng)站將在24小時內(nèi)刪除侵權(quán)內(nèi)容。
版權(quán)聲明:本文內(nèi)容由網(wǎng)絡(luò)用戶投稿,版權(quán)歸原作者所有,本站不擁有其著作權(quán),亦不承擔(dān)相應(yīng)法律責(zé)任。如果您發(fā)現(xiàn)本站中有涉嫌抄襲或描述失實(shí)的內(nèi)容,請聯(lián)系我們jiasou666@gmail.com 處理,核實(shí)后本網(wǎng)站將在24小時內(nèi)刪除侵權(quán)內(nèi)容。