From:深入理解Java虛擬機
- 目錄
BiBi - JVM -0- 開篇
BiBi - JVM -1- Java內(nèi)存區(qū)域
BiBi - JVM -2- 對象
BiBi - JVM -3- 垃圾收集算法
BiBi - JVM -4- HotSpot JVM
BiBi - JVM -5- 垃圾回收器
BiBi - JVM -6- 回收策略
BiBi - JVM -7- Java類文件結(jié)構(gòu)
BiBi - JVM -8- 類加載機制
BiBi - JVM -9- 類加載器
BiBi - JVM -10- 虛擬機字節(jié)碼
BiBi - JVM -11- 編譯期優(yōu)化
BiBi - JVM -12- 運行期優(yōu)化
BiBi - JVM -13- 并發(fā)
新生代:Serial瞪讼、ParNew食呻、Parallel Scavenge、G1
老年代:Serial Old辫愉、CMS署辉、Parallel Old族铆、G1
并行【Parallel】:指多條垃圾收集線程并行工作,但此時用戶線程仍然處于等待狀態(tài)哭尝。
并發(fā)【Concurrent】:指用戶線程與垃圾收集線程同時執(zhí)行【但不一定是并行的哥攘,可能會交替執(zhí)行】,用戶程序在繼續(xù)運行刚夺。而垃圾收集程序運行在另一個CPU上献丑。
1. Serial收集器
單線程收集器,在進行垃圾收集時侠姑,必須暫停其他所有的工作線程创橄,直到收集結(jié)束。是虛擬機運行在Client模式下的默認(rèn)【新生代】收集器莽红。與其他收集器相比的優(yōu)勢:沒有線程交互的開銷妥畏,專心做垃圾收集邦邦,簡單高效。
2. ParNew收集器
是Serial收集器的多線程版本醉蚁。是虛擬機運行在Service模式下首選【新生代】收集器燃辖。一個原因是:除了Serial收集器外,只有ParNew能與CMS收集器配合使用网棍。即新生代多線程收集器能與CMS收集器的就ParNew這么一個黔龟。當(dāng)CPU數(shù)量增多時【CPU > 2】,它的性能才會超越Serial收集器滥玷。
3. Parallel Scavenge收集器【吞吐量優(yōu)先收集器】
是新生代并行的多線程收集器氏身。其它收集器的關(guān)注點都是盡可能地縮短垃圾收集時用戶線程的停頓時間,而Parallel Scavenge收集器的目標(biāo)是達到一個可控制的吞吐量惑畴。
吞吐量 = 運行用戶代碼時間 / (運行用戶代碼時間 + 垃圾收集時間)
停頓時間越短就越適合需要與用戶交互的程序蛋欣,提高響應(yīng)速度,改善用戶體驗如贷;
高吞吐量可以高效利用CPU時間陷虎,適合在后臺運算而【不需要太多交互的任務(wù)】。
與ParNew收集器一個重要區(qū)別:Parallel Scavenge具有【GC自適應(yīng)的調(diào)節(jié)策略】杠袱,即虛擬機能根據(jù)當(dāng)前系統(tǒng)的運行情況收集性能監(jiān)控信息尚猿,動態(tài)調(diào)整新生代中Eden與Survivor的比例,以提供最適合的停頓時間或最大的吞吐量楣富。
注:Parallel Scavenge收集器和G1收集器沒有使用傳統(tǒng)的GC收集器代碼框架谊路,可能基于這個原因他們不能與CMS收集器配合使用。
4. Serial Old收集器
單線程老年代收集器菩彬,主要在Client模式下使用缠劝。
5. Parallel Old收集器
多線程老年代收集器,適用于:注重吞吐量以及CPU資源敏感的場合骗灶。
6. CMS收集器【并發(fā)收集惨恭,低停頓】
CMS【Concurrent Mark Sweep,并發(fā)標(biāo)記清除】采用【標(biāo)記 - 清除】算法的老年代收集器耙旦,而Serial Old和Parallel Old采用的是【標(biāo)記 - 整理】算法脱羡。
-
CMS收集器工作的步驟
1)初始標(biāo)記 【需要stop the world】
僅僅只是標(biāo)記GC Roots直接關(guān)聯(lián)到的對象,速度很快免都。
2)并發(fā)標(biāo)記
進行GC Roots Tracing過程锉罐。
3)重新標(biāo)記【需要stop the world】
修正并發(fā)標(biāo)記期間因用戶程序繼續(xù)運作而導(dǎo)致標(biāo)記發(fā)生變動的那一個部分對象的標(biāo)記記錄,這個階段停頓的時間會比初始標(biāo)記階段稍長绕娘。
4)并發(fā)清除
整個過程中耗時最長的并發(fā)標(biāo)記和并發(fā)清除過程脓规,但是這兩個過程都可以與用戶線程一起工作。所以险领,從整體上來說侨舆,CMS收集器的內(nèi)存回收過程是與用戶線程一起并發(fā)執(zhí)行的秒紧。
-
CMS收集器的問題
1)并發(fā)階段,會因占用一部分線程而導(dǎo)致應(yīng)用程序變慢挨下,總吞吐量降低熔恢。當(dāng)CPU負(fù)載較大時,還要分出一半的運算能力去執(zhí)行收集器線程臭笆,可能導(dǎo)致用戶程序的執(zhí)行速度忽然降低50%叙淌,這是難以接受的。
解決:采用【增量式并發(fā)收集器】的CMS收集器變種愁铺,所做的事情和單CPU年代PC機操作系統(tǒng)使用【搶占式模擬多任務(wù)機制】的思想一樣凿菩,在并發(fā)標(biāo)記和清理的時候,讓GC線程帜讲、用戶線程交替運行,盡量減少GC線程獨占資源的時間椒拗。這樣這個垃圾收集的過程會更長似将,但對用戶程序的影響會減少∈纯粒【效果一般在验,現(xiàn)在已經(jīng)被棄用】
2)由于CMS并發(fā)清理垃圾時,用戶線程還在運行堵未,也會產(chǎn)生新的垃圾腋舌,這一部分垃圾CMS無法當(dāng)次處理,只能等待下一次GC時再清理渗蟹,這部分垃圾稱為【浮動垃圾】块饺。所以CMS不能像其他收集器那樣,等到老年代幾乎被填滿時再進行收集雌芽,JDK1.5閾值為68%授艰,JDK1.6閾值為92%【老年代使用了92%的內(nèi)存后觸發(fā)GC】。
所以世落,當(dāng)CMS運行期間預(yù)留的內(nèi)存無法滿足浮動垃圾占用的內(nèi)存淮腾,就會出現(xiàn)一次 Concurrent Mode Failure 失敗,這時會啟動預(yù)備方案:使用Serial Old收集器來重新進行老年代的垃圾收集屉佳,這樣停頓的時間就很長了谷朝,導(dǎo)致性能降低。
3)CMS采用【標(biāo)記-清除】算法武花,會產(chǎn)出大量碎片空間圆凰。解決:在CMS進行FullGC時進行內(nèi)存碎片合并整理過程,該過程無法并發(fā)体箕∷椭欤或者設(shè)置執(zhí)行多少次不壓縮的FullGC后娘荡,進行一次帶壓縮的。
7. G1【Garbage-First】收集器
是一款面向服務(wù)端應(yīng)用的垃圾收集器驶沼。不需要其他收集器配合就能獨立管理整個GC堆炮沐,它能夠采用不同的處理方式去處理新創(chuàng)建的對象、已存活一段時間回怜、熬過多次GC的舊對象以獲取更好的收集效果大年。
G1從整體看是基于【標(biāo)記-整理】算法,從局部看是基于【復(fù)制】算法玉雾,這意味著G1不會產(chǎn)生內(nèi)存空間碎片翔试。
-
可預(yù)測的停頓
這是比CMS的另一大優(yōu)勢,G1能讓使用者明確指定在一個長度為M毫秒的時間片段內(nèi)复旬,消耗在垃圾收集上的時間不得超過N毫秒垦缅。【依據(jù)Region:它可以有計劃地避免在整個Java堆中進行全局的垃圾回收】
-
Region
其它收集器進行收集的范圍是整個新生代或者老年代驹碍,而G1不是壁涎,它將整個Java堆劃分為多個大小相等的獨立區(qū)域【Region】,雖然還保留新生代和老年代的概念志秃,但是新生代和老年代不再是物理隔離的了怔球,它們都是一部分Region【不需要連續(xù)】的集合。
-
回收思路
G1跟蹤各個Region里面的垃圾堆積的價值大小浮还,在后臺維護一個優(yōu)先列表竟坛,每次根據(jù)允許的收集時間,優(yōu)先回收價值最大的Region【這也是Garbage-First的由來】钧舌。其中担汤,垃圾堆的價值大小體現(xiàn)在:回收所獲得的空間大小和回收所需時間。
Region的劃分和有優(yōu)先級的回收洼冻,保證G1在有限時間內(nèi)獲取盡可能高的收集效率漫试。
-
問題
問題:Region不可能是孤立的,一個對象并不只能被本Region中的其它對象引用碘赖,而是整個Java堆中的任意對象都可以引用它驾荣。在做可達性分析對象是否存活時,要掃描整個Java堆嗎普泡?跟其它收集器也有一樣的問題播掷,回收新生代時,要掃描整個老年代嗎撼班?
解決:在G1收集器中歧匈,Region之間的對象引用以及其他收集器中的新生代和老年代之間的對象引用,虛擬機都是使用Remembered Set來避免全堆掃描的砰嘁。G1中每個Region都有一個與之對應(yīng)的Remember Set件炉,虛擬機發(fā)現(xiàn)程序在對Reference類型的數(shù)據(jù)進行寫操作時勘究,會產(chǎn)生一個Writer Barrier暫時中斷寫操作,檢查Reference引用的對象是否處于不同的Region之中【在分代的例子中就是檢查是否老年代中的對象引用了新生代中的對象】斟冕,如果是便通過CardTable把相關(guān)引用信息記錄到被引用對象所屬的Region的Remember Set之中口糕。當(dāng)進行內(nèi)存回收時,在GC根節(jié)點的枚舉范圍中加入Remember Set即可保證不對全堆掃描也不會有遺漏磕蛇。
-
G1收集過程【與CMS類似】
1)初始標(biāo)記
2)并發(fā)標(biāo)記
3)最終標(biāo)記
為了修正在并發(fā)標(biāo)記期間因用戶程序繼續(xù)運作而導(dǎo)致標(biāo)記產(chǎn)生變動的那一部分標(biāo)記記錄景描,虛擬機將這段時間對象變化記錄在線程Remember Set Logs里面,最終標(biāo)記階段需要把Remember Set Logs的數(shù)據(jù)合并到Remember Set中秀撇,這個階段需要停頓其它線程超棺,但可并行執(zhí)行。
4)篩選回收
首先對各個Region的回收價值和成本進行排序呵燕,根據(jù)用戶所期望的GC停頓時間來制定回收計劃棠绘。這個階段也是可以做到和用戶線程一起并發(fā)執(zhí)行,
追求低停頓再扭,可以嘗試G1氧苍;追求吞吐量,暫時不建議嘗試G1霍衫。