垃圾收集算法
標(biāo)記清除(會(huì)有內(nèi)存碎片,大對(duì)象時(shí)更有可能因?yàn)闆]有足夠的連續(xù)內(nèi)存而觸發(fā)GC芬骄,但是可以降低了STW的時(shí)間)
復(fù)制算法(優(yōu)點(diǎn)是沒有碎片,缺點(diǎn)是浪費(fèi)空間和復(fù)制過程中會(huì)STW,需要有專門的空白的內(nèi)存塊來存儲(chǔ)復(fù)制過來的對(duì)象姻僧,而且在復(fù)制的過程中需要STW撇贺。年輕代適合復(fù)制算法挎扰,默認(rèn)犧牲1/10的空間:Survivor to區(qū))遵倦,適合大部分都是垃圾的業(yè)務(wù)場(chǎng)景,年輕代棘脐。
標(biāo)記整理(或者也叫標(biāo)記壓縮蛀缝,避免了內(nèi)存碎片,同時(shí)也避免了復(fù)制算法的內(nèi)存空間浪費(fèi)在讶,但是壓縮的時(shí)候涉及到內(nèi)存地址的移動(dòng),此期間還是會(huì)STW)战坤,適合大部分都不是垃圾的業(yè)務(wù)場(chǎng)景碟嘴,老年代
分代回收:老年代和年輕代
其它細(xì)節(jié)
并發(fā)指的是同時(shí)發(fā)生栅组,比如一邊GC回收玉掸,一邊程序運(yùn)行排截,用戶行為不會(huì)受到影響断傲。并行指的是一個(gè)相同的操作同時(shí)多個(gè)線程來執(zhí)行箱蝠,比如ParNew多個(gè)線程同時(shí)進(jìn)行YGC宦搬。
垃圾收集器的搭配是有限定的矾克,不是任意都可以搭配。
垃圾回收器
年輕代回收器:Serial滓彰、Parallel Scanvenge、ParNew
老年代回收器:Serial Old菇存、Parallel Old、CMS
綜合回收器:G1
- Serial & Serial_Old 收集器
- 分為年輕代Serial(復(fù)制算法) 和老年代的 Serial Old(標(biāo)記整理算法)
- 串行回收,高效 穩(wěn)定但是stop the world較長(zhǎng)
- 適合單核CPU关筒,效率高而且穩(wěn)定蒸播,避免了線程切換的開銷
- 是Client模式下的默認(rèn)GC機(jī)制
- Serial Old是CMS PromotionFailure后的默認(rèn)替代回收器
ParNew回收器:CMS的最佳伴侶塘揣,因?yàn)镃MS只能和Serial和ParNew配合使用才写,而ParNew是多線程版本的Serial
Parallel Scavenge回收器:多線程赞草,追求高吞吐量(運(yùn)行代碼時(shí)間/運(yùn)行代碼時(shí)間+GC時(shí)間) 和參數(shù)自動(dòng)調(diào)整
- 支持配置GCMaxPause和GCTimeRatio兩個(gè)參數(shù)洲守,來控制GC最大停頓時(shí)間和吞吐量搭独,默認(rèn)99%
- 支持配置UseAdaptiveSizePolicy牙肝,自動(dòng)調(diào)整年輕代 Eden、S0、S1區(qū)的大小和晉升老年代ratio敦姻,從而來滿足上面的兩個(gè)參數(shù)
- 不能和CMS一起搭配使用,而和SerialOld搭配又浪費(fèi),所以一般都是和Parallel Old搭配使用
- Parallel Old:標(biāo)記整理茵瘾,吞吐量?jī)?yōu)先,追請(qǐng)的是性能最大化晨雳,比如一些后臺(tái)計(jì)算類突照,報(bào)表生成類的應(yīng)用
CMS收集器
適合多CPU座慰,頻繁和用戶交互的業(yè)務(wù)場(chǎng)景游盲,追求的是停頓時(shí)間最短,采用標(biāo)記清除的回收算法(因?yàn)闃?biāo)記清除不會(huì)涉及存活對(duì)象的移動(dòng):復(fù)制和壓縮,從而降低STW的時(shí)間)
回收4個(gè)階段
- 初始標(biāo)記:STW,快速獲取到老年代中的GC Roots對(duì)象令哟,以及遍歷新生代中GC Roots對(duì)象引用到老年代中的對(duì)象滑燃, 默認(rèn)是單線程執(zhí)行典予,也可以設(shè)置多線程數(shù)并行進(jìn)行捂敌。
- 并發(fā)標(biāo)記:并發(fā)客戶線程逆济,只分配一個(gè)線程來根據(jù)初始標(biāo)記里面的對(duì)象開始奖慌,逐個(gè)標(biāo)記 初始標(biāo)記成功的對(duì)象的引用的對(duì)象。如果并發(fā)期間,對(duì)象的引用關(guān)系發(fā)生改變蹦浦,則會(huì)被標(biāo)記為dirty對(duì)象盲镶。
- 重新標(biāo)記:STW溉贿,修正并發(fā)標(biāo)記期間浦旱,引用關(guān)系的改變,這個(gè)過程比初始標(biāo)記稍長(zhǎng)颁湖。
- 并發(fā)清除:專門分配一個(gè)線程來清除標(biāo)記過的對(duì)象甥捺,不影響用戶操作,此階段會(huì)有新的浮動(dòng)垃圾生成镰禾,如果太多唱逢,會(huì)造成PromotionFailure
CMS的缺點(diǎn)
- 對(duì)CPU資源敏感屋休,因?yàn)樵诓l(fā)標(biāo)記、并發(fā)清除的時(shí)候都需要占用一個(gè)單獨(dú)的線程來完成操作绸贡,如果CPU為2的話毅哗,那么就只有1個(gè)CPU能干活,一個(gè)CPU在GC
- 無法處理浮動(dòng)垃圾尿瞭,也就是每次GC都掃不干凈翅睛,因?yàn)椴l(fā)清除的過程中,還會(huì)有新的垃圾產(chǎn)生捕发,而且如果這個(gè)階段新的垃圾導(dǎo)致空間不足,會(huì)PromotionFailure
- 基于標(biāo)記清除算法會(huì)存在很多碎片檐涝,空間利用率不高法挨,需要配置壓縮參數(shù),但是在壓縮的過程中STW的時(shí)間會(huì)延長(zhǎng)
G1回收器
吞吐量和最短停頓時(shí)間本來就互相矛盾窃植,Parallel Old追求的是吞吐量荐糜,CMS追求的是STW的最短,而G1通過把堆分成多個(gè)相對(duì)獨(dú)立的Region塊暴氏,并行的進(jìn)行選擇性的回收偏序,實(shí)現(xiàn)一個(gè)兩者兼顧的回收器。
G1類似于CMS研儒,G1回收器支持用戶并發(fā)操作独令,MajorGC在并發(fā)標(biāo)記時(shí)允許用戶線程同時(shí)進(jìn)行業(yè)務(wù)操作燃箭。
G1相對(duì)CMS而言舍败,更加靈活,因?yàn)閮?nèi)部是多個(gè)Rigion組成邻薯,而且每個(gè)Rigion是獨(dú)立的(Rigion之間對(duì)象的相互引用記錄在Remembered Set里面),所以可以根據(jù)用戶設(shè)定的允許最長(zhǎng)停頓時(shí)間累榜,在一次MajorGC的過程中只回收部分Rigion(回收空間價(jià)值最高而經(jīng)驗(yàn)推算的時(shí)間成本又最低的Rigion塊灵嫌,比如Rigion1對(duì)象活躍度10%,Rigion2對(duì)象活躍度50%猖凛,那么優(yōu)先回收Rigion1塊)绪穆,這是CMS無法做到的,CMS的老年代是完整的一塊內(nèi)存,要GC的話量瓜,就必須整個(gè)老年代全部GC,而整個(gè)老年代全部GC的話扔傅,停頓的時(shí)間就會(huì)相對(duì)更長(zhǎng)烫饼。年輕代來看,也更加靈活杠纵,因?yàn)槟贻p代的Eden區(qū)和S區(qū)的Rigion塊數(shù)量是動(dòng)態(tài)調(diào)整的比藻。
G1相對(duì)CMS而言倘屹,因?yàn)椴捎玫氖菑?fù)制算法慢叨,所以沒有內(nèi)存碎片的產(chǎn)生。避免了堆中大對(duì)象因?yàn)闆]有足夠的連續(xù)的內(nèi)存空間而觸發(fā)MajorGC的情況烛缔。其實(shí)CMS之所以使用標(biāo)記清除算法轩拨,是為了減少壓縮垃圾過程時(shí)的STW,因?yàn)镚1可以做到部分而不是所有Rigion塊的GC气嫁,所以可以在預(yù)測(cè)的時(shí)間內(nèi)完成復(fù)制操作。
G1的適合大內(nèi)存的JVM環(huán)境崖面。因?yàn)椴捎脧?fù)制的算法(YGC和MajorGC都是復(fù)制)梯影,所以需要有一定的空閑內(nèi)存塊來存儲(chǔ)復(fù)制來的對(duì)象,空間利用率低。而且每次GC都不是完整的GC简识,需要該Region塊的活躍度低于一定標(biāo)準(zhǔn)感猛,這個(gè)Region塊才會(huì)發(fā)起回收,所以一些活躍度高的內(nèi)存塊里面的垃圾對(duì)象不會(huì)被回收掉,默認(rèn)堆內(nèi)存使用率達(dá)到45%的時(shí)候颈走,就開始FullGC咱士。
G1適合多CPU的JVM環(huán)境。因?yàn)閭鹘y(tǒng)的回收器都是3個(gè)內(nèi)存塊序厉,而G1默認(rèn)是2000多個(gè)相對(duì)獨(dú)立的內(nèi)存塊弛房,在GC幾乎所有的過程中,Region塊都是高度并行化的進(jìn)行回收,而且還有在并發(fā)標(biāo)記階段支持用戶并發(fā)性的業(yè)務(wù)操作牺堰,所以對(duì)CPU的要求較高
G1的靈活性還在于能夠根據(jù)設(shè)置的STW時(shí)間颅围,動(dòng)態(tài)調(diào)整各個(gè)分代的內(nèi)存占比,有點(diǎn)類似于Parallel Old筏养,但是和CMS是不同的常拓。
G1回收器FullGC回收過程
- 初始標(biāo)記,STW茎辐,分為老年代和年輕代兩部分掂恕。先會(huì)觸發(fā)一次YGC(排除掉年輕代對(duì)老年代有引用,但是該年輕代對(duì)象已經(jīng)死亡的情況)懊亡,然后再對(duì)Survivor to區(qū)進(jìn)行遍歷(確保所有的年輕代的對(duì)象都是活的店枣,因?yàn)榻?jīng)歷了一次YGC),查找并標(biāo)記S區(qū)對(duì)象對(duì)老年代的直接引用的所有老年代對(duì)象(這里是直接引用鸯两,比如Survivor to區(qū)A對(duì)象,引用了老年代的B對(duì)象忙灼,就標(biāo)記B對(duì)象逾柿,雖然B對(duì)象還可能引用了C宅此、D、E對(duì)象)弱匪。第二部分是針對(duì)老年代,標(biāo)記老年代中所有GC Roots直接引用的對(duì)象斥难。
- 并發(fā)標(biāo)記帘饶,根據(jù)可達(dá)性分析,找到所有GCRoots的對(duì)象引用及刻,一層一層的標(biāo)記,這個(gè)時(shí)候沒有STW暑劝,用戶線程正常執(zhí)行颗搂。
- 最終標(biāo)記,STW傅联,修正并發(fā)標(biāo)記期間的對(duì)象關(guān)系變更卖丸,根據(jù)Remembered Set Logs,來修改Remember Set载碌,該階段可以多個(gè)線程并行
- 篩選回收衅枫,STW,會(huì)跟蹤各個(gè)Rigion里面的垃圾堆積的價(jià)值大胁竭洹(比如需要回收的對(duì)象的空間大小以及回收所需時(shí)間的經(jīng)驗(yàn)值)排序,根據(jù)用戶設(shè)定的停頓時(shí)間益楼,回收特定Region,因?yàn)槊總€(gè)Region塊都有獨(dú)立的Remembered Set感凤,所以每個(gè)Region可以獨(dú)立的進(jìn)行回收陪竿,也就是多個(gè)Region塊并行多線程的垃圾回收。
G1回收的細(xì)節(jié)
- 當(dāng)執(zhí)行垃圾回收時(shí),G1以類似于CMS回收器的方式運(yùn)行锐墙。G1執(zhí)行一個(gè)并發(fā)的全局標(biāo)記階段长酗,以確定整個(gè)堆中對(duì)象的活躍度。
- G1使用一個(gè)暫停預(yù)測(cè)模型來滿足用戶定義的暫停時(shí)間目標(biāo)并基于指定的暫停時(shí)間目標(biāo)選擇回收的區(qū)域數(shù)量
- G1因?yàn)榻?jīng)常性的不完整GC刻盐,活躍度高的內(nèi)存塊GC的會(huì)更晚劳翰,而且需要有空閑的Region來實(shí)現(xiàn)復(fù)制,進(jìn)行垃圾回收的時(shí)機(jī)更早乙墙,默認(rèn)在堆內(nèi)存使用率達(dá)到45%時(shí)就會(huì)開始垃圾回收生均。這體現(xiàn)了G1(Garbage-First/垃圾回收優(yōu)先)這一名字的含義。至于活躍度多低才會(huì)進(jìn)行回收汉买,則是由G1決定的佩脊,G1會(huì)調(diào)整自己的回收策略來盡可能滿足用戶設(shè)置的最大STW時(shí)長(zhǎng)。
- 每個(gè)Rigion都有一個(gè)Remembered Set出牧,來紀(jì)錄Region塊之間的對(duì)象引用歇盼,RSet使得區(qū)域并行獨(dú)立的回收成為可能。當(dāng)程序發(fā)生寫操作的時(shí)候伯复,會(huì)判斷相關(guān)的引用是否涉及到跨Region的引用邢笙,比如Rigion0當(dāng)中,A對(duì)象之前是引用Rigion0中的B對(duì)象组底,現(xiàn)在執(zhí)行程序筐骇,A對(duì)象被重新賦值,引用了Rigion1中的C對(duì)象厌均,那么在Rigion1的Remembered Set當(dāng)中就要紀(jì)錄告唆,否則Region1在GC的時(shí)候,會(huì)把C對(duì)象直接回收了模她,通過讀取自己的Remembered Set知道C對(duì)象被Region0種的A對(duì)象引用懂牧,這樣既避免了全堆的掃描,又實(shí)現(xiàn)了分塊管理畜侦。
- FullGC觸發(fā)的時(shí)機(jī)是內(nèi)存使用率達(dá)到一定的比例躯保,默認(rèn)45%
G1中的年輕代,可以說明一下幾點(diǎn):
- YGC觸發(fā)的條件是Eden區(qū)滿了
- Survivor To塊可以認(rèn)為是一個(gè)空白塊验懊,因?yàn)閅GC和MajorGC都是采用復(fù)制算法盯孙,都是復(fù)制到一個(gè)空白的內(nèi)存塊當(dāng)中。
- 年輕代垃圾回收使用多線程并行進(jìn)行歌溉,需要STW
- 年輕代內(nèi)存由一組非連續(xù)的區(qū)域組成骑晶,而且Eden、S區(qū)的大小是動(dòng)態(tài)調(diào)整的
- 存活對(duì)象被拷貝到新的幸存區(qū)或者年老代區(qū)域(超過存活ratio的對(duì)象進(jìn)入老年代)