1. 對(duì)象存活判斷
1.1. 引用計(jì)數(shù)算法 Reference Counting
- 給對(duì)象添加一個(gè)引用計(jì)數(shù)器砾省,每當(dāng)有一個(gè)地方引用它的時(shí)候,計(jì)數(shù)器值就加一沸手;當(dāng)引用失效時(shí)内边,計(jì)數(shù)器值就減一;任何時(shí)刻計(jì)數(shù)器為0的對(duì)象就是不可能再被使用的索绪。
- 主流的JVM沒有選用引用計(jì)數(shù)算法來管理內(nèi)存湖员,主要的原因是它很難解決對(duì)象之間的相互循環(huán)引用的問題。
1.2. 可達(dá)性分析算法 Reachability Analysis
- 通過一系列稱為“GC-Roots”的對(duì)象作為起點(diǎn)瑞驱,從這些結(jié)點(diǎn)開始向下搜索娘摔,搜索所走過的路徑稱為引用鏈(Reference Chain),當(dāng)一個(gè)對(duì)象到GC Roots沒有任何引用鏈相連時(shí)唤反,則證明此對(duì)象是不可用的(圖論中的不可達(dá))凳寺。
- 可作為GC Roots的對(duì)象:
虛擬機(jī)棧(戰(zhàn)爭(zhēng)中的本地變量表)中引用的對(duì)象
方法區(qū)中類靜態(tài)屬性引用的對(duì)象
方法區(qū)中常量引用的對(duì)象
本地方法棧中JNI引用的對(duì)象
1.3. 引用類型 Reference
- 強(qiáng)引用:Strong Reference
指的是類似于
Object object = new Object()
這類引用,只要強(qiáng)引用存在彤侍,垃圾收集器就永遠(yuǎn)不會(huì)回收被引用對(duì)象肠缨。
- 軟引用:Soft Reference
描述一些還有用但并非必要的對(duì)象。JDK提供了SoftReference來實(shí)現(xiàn)軟引用
在系統(tǒng)快要發(fā)生內(nèi)存溢出之前盏阶,將會(huì)把這些對(duì)象列進(jìn)回收范圍之中進(jìn)行第二次回收晒奕。如果這次回收還沒有足夠的內(nèi)存,才會(huì)拋出內(nèi)存溢出異常名斟。
- 弱引用: Weak Reference
用來描述非必須對(duì)象脑慧,它的強(qiáng)度比軟引用更弱一些,被弱引用關(guān)聯(lián)的對(duì)象只能生存到下一次垃圾收集發(fā)生之前砰盐。JDK提供了WeakReference類來實(shí)現(xiàn)弱引用闷袒。
當(dāng)垃圾收集器工作時(shí),無論當(dāng)前內(nèi)存是否足夠楞卡,都會(huì)回收掉只被弱引用關(guān)聯(lián)的對(duì)象霜运。
- 虛引用:Phantom Reference
也稱為幽靈引用或幻影引用脾歇,它是最弱的一種引用關(guān)系。一個(gè)對(duì)象是否有虛引用的存在淘捡,完全不會(huì)對(duì)其生存時(shí)間構(gòu)成影響藕各,也無法通過虛引用來取得一個(gè)對(duì)象實(shí)例。JDK提供PhantomReference類來實(shí)現(xiàn)虛引用
為一個(gè)對(duì)象設(shè)置虛引用關(guān)聯(lián)的唯一目的就是能在這個(gè)對(duì)象被收集器回收時(shí)收到一個(gè)系統(tǒng)通知焦除。
1.3. 引用類型 Reference
-
不可達(dá)對(duì)象激况,會(huì)暫時(shí)處于“緩刑”階段,要真正宣告一個(gè)對(duì)象死亡,至少要經(jīng)歷兩次標(biāo)記過程:
如果對(duì)象在進(jìn)行可達(dá)性分析后發(fā)現(xiàn)沒有與GC Roots相連接的引用鏈,那它將會(huì)被第一次標(biāo)記并且進(jìn)行一次篩選,篩選的條件是此對(duì)象是否有必要執(zhí)行finalize()方法。當(dāng)對(duì)象沒有覆蓋finalize()方法,或者finalize()方法已經(jīng)被虛擬機(jī)調(diào)用過,虛擬機(jī)將這兩種情況都視為“沒有必要執(zhí)行”膘魄。
finalize()方法是對(duì)象逃脫死亡命運(yùn)的最后一次機(jī)會(huì),稍后GC將對(duì)F-Queue中的對(duì)象進(jìn)行第二次小規(guī)模的標(biāo)記,如果對(duì)象要在finalize()中成功拯救自己——只要重新與引用鏈上的任何一個(gè)對(duì)象建立關(guān)聯(lián)即可,譬如把自己(this關(guān)鍵字)賦值給某個(gè)類變量或者對(duì)象的成員變量,那在第二次標(biāo)記時(shí)它將被移除出“即將回收”的集合;如果對(duì)象這時(shí)候還沒有逃脫,那基本上它就真的被回收了乌逐。
注:如果對(duì)象唄判定有必要執(zhí)行finalize()方法,那么這個(gè)對(duì)象將會(huì)放置在一個(gè)叫做F-Queue隊(duì)列中创葡,并隨后JVM會(huì)創(chuàng)建一個(gè)低優(yōu)先級(jí)的Finalizer線程去執(zhí)行它浙踢。JVM觸發(fā)這個(gè)方法,并不確保它會(huì)執(zhí)行結(jié)束灿渴,因?yàn)槿绻麑?duì)象finalize方法如果執(zhí)行緩慢或者死循環(huán)洛波,將很有可能會(huì)導(dǎo)致F-Queue隊(duì)列其他對(duì)象永久等待,甚至導(dǎo)致整個(gè)內(nèi)存回收系統(tǒng)奔潰骚露。
2. 垃圾收集算
2.1. 標(biāo)記-清除算法 Mark-Sweep
-
算法分兩個(gè)階段蹬挤,即標(biāo)記和清除。
- 標(biāo)記處所需要回收的對(duì)象
- 標(biāo)記完成后統(tǒng)一回收所有被標(biāo)記對(duì)象
-
算法主要不足
- 效率問題棘幸,標(biāo)記和清除兩個(gè)過程效率都不高
- 空間問題焰扳,標(biāo)記清除后悔產(chǎn)生大量不連續(xù)的空間
空間碎片太多可能會(huì)導(dǎo)致以后分配大對(duì)象時(shí)無法找到足夠連續(xù)內(nèi)存存放而不得不觸發(fā)另一次垃圾收集。
2.2. 復(fù)制算法 Copying
- 將可用的內(nèi)存按照容量劃分為大小相等的兩塊误续,每次使用其中一塊吨悍。當(dāng)前一塊用完了,將還存活的對(duì)象移動(dòng)到另一塊上面女嘲,然后把已使用過的內(nèi)存空間一次性清理掉畜份。這樣每次都是堆整個(gè)半?yún)^(qū)進(jìn)行內(nèi)存回收,分配內(nèi)存時(shí)也就不考慮內(nèi)存碎片等復(fù)雜情況欣尼,實(shí)現(xiàn)簡(jiǎn)單、運(yùn)行高效停蕉。代價(jià)是將內(nèi)存縮小為原來的一半愕鼓。
2.3. 標(biāo)記-整理算法 Mark-Compact
- 標(biāo)記后不直接對(duì)可回收對(duì)象清理,而是讓所有存活的對(duì)象都向一端移動(dòng)慧起,然后直接清理掉端邊界以為的內(nèi)存菇晃。
2.4. 分代收集算法 Generational Collection
-
把JVM堆內(nèi)存分為新生代和老年代,對(duì)不同的年代采取不同的收集算法蚓挤。
在新生代中每次垃圾收集時(shí)都發(fā)現(xiàn)有大批對(duì)象死去磺送,只有少量存活驻子,那就選用復(fù)制算法。
老年代中因?yàn)閷?duì)象存活率高估灿、沒有額外空間對(duì)它進(jìn)行分配擔(dān)保崇呵,那就必須使用“標(biāo)記-清理”或“標(biāo)記-整理”算法來進(jìn)行回收。
3. 垃圾收集算
3.1. 枚舉根節(jié)點(diǎn)
- 可達(dá)性分析從GC Roots節(jié)點(diǎn)找引用鏈操作馅袁,現(xiàn)在引用僅方法區(qū)就有數(shù)百兆域慷,逐個(gè)檢查里面的引用非常耗時(shí)。
- 可達(dá)性分析對(duì)執(zhí)行時(shí)間的敏感上體現(xiàn)在GC停頓上汗销,這項(xiàng)分析工作必須在一個(gè)能確保一致性的快照中犹褒,
這里的一致性是指在整個(gè)分析期間整個(gè)執(zhí)行系統(tǒng)開起來像被凍結(jié)在某個(gè)時(shí)間節(jié)點(diǎn)上。如果這點(diǎn)不滿足準(zhǔn)確性就無法保證弛针。這是導(dǎo)致GC進(jìn)行時(shí)必須停頓所有Java執(zhí)行線程的其中一個(gè)重要原因叠骑。即使在CMS收集器(號(hào)稱幾乎不發(fā)生停頓)中枚舉根節(jié)點(diǎn)也是必須要停頓的。
- 主流的JVM都是使用的準(zhǔn)確式GC削茁,所以當(dāng)執(zhí)行系統(tǒng)停頓下來并不需要一個(gè)不漏檢查完所有執(zhí)行上下文和全局的引用位置宙枷,JVM知道哪里存放這個(gè)信息,在HotSpot使用了一組OopMap的數(shù)據(jù)結(jié)構(gòu)來達(dá)到這個(gè)目的付材。
在類加載完后朦拖,HotSpot吧對(duì)象內(nèi)的各個(gè)偏移量上的類型計(jì)算出來,在JIT編譯過程中厌衔,也會(huì)在特定的位置記錄下棧和寄存器中哪些位置是引用璧帝。在GC掃描時(shí),就可以直接知道這些信息富寿。
3.2. 安全點(diǎn) Safepoint
HotSpot在特定的位置記錄棧和寄存器中哪些位置是引用睬隶,這個(gè)“特定位置”就稱為“安全點(diǎn)”,即程序執(zhí)行時(shí)并非在所有地方都能停頓下來開始GC页徐,只有在到達(dá)安全點(diǎn)時(shí)才能暫停苏潜。
-
安全點(diǎn)不能太多,也不能太少变勇,太多增大系統(tǒng)負(fù)荷恤左,太少GC等待時(shí)間太長(zhǎng)。所以安全點(diǎn)的選擇基本是以“是否具有讓程序長(zhǎng)時(shí)間執(zhí)行的特征”為標(biāo)準(zhǔn)選定搀绣。
因?yàn)槊織l指令執(zhí)行時(shí)間都非常短暫飞袋,程序不太可能因?yàn)橹噶盍鏖L(zhǎng)度太長(zhǎng)而過長(zhǎng)時(shí)間運(yùn)行,所以長(zhǎng)時(shí)間的特征就是指令序列復(fù)用链患、循環(huán)跳轉(zhuǎn)巧鸭、異常跳轉(zhuǎn)等
-
怎樣確保GC發(fā)生所有線程都跑到安全點(diǎn)再停頓下來,有兩種方案:
搶先式中斷(Preemptive Suspension):在發(fā)生GC時(shí)麻捻,首先把所有線程全部中斷纲仍,如果發(fā)現(xiàn)有線程中斷的地方不在安全點(diǎn)上呀袱,就恢復(fù)線程,讓它跑到安全點(diǎn)上郑叠。
主動(dòng)式中斷(Voluntary Suspension):當(dāng)GC需要中斷線程時(shí)夜赵,不對(duì)線程直接操作,僅簡(jiǎn)單設(shè)置一個(gè)標(biāo)志锻拘,各個(gè)線程執(zhí)行時(shí)主動(dòng)去輪詢這個(gè)標(biāo)志油吭,發(fā)現(xiàn)中斷標(biāo)志為真的時(shí)候就自己把中斷掛起。輪詢標(biāo)志這個(gè)地方和安全點(diǎn)是重合的署拟,另外再加上創(chuàng)建對(duì)象需要分配內(nèi)存的地方婉宰。
3.3. 安全區(qū)域 Safe Region
- 安全區(qū)域是指一段代碼片段中,引用關(guān)系不會(huì)發(fā)發(fā)生變化推穷。在這個(gè)區(qū)域中的任意地方開始GC都是安全的心包。
- 在線程執(zhí)行到Safe Region中的代碼時(shí),首先表示自己進(jìn)入了Safe Region馒铃,這這段時(shí)間里蟹腾,JVM要發(fā)起GC時(shí),就不用管標(biāo)識(shí)自己為Safe Region狀態(tài)的線程了区宇。在線程要離開Safe Region時(shí)娃殖,它要檢查系統(tǒng)是否已經(jīng)完成了根節(jié)點(diǎn)枚舉(或者整個(gè)GC過程),如果完成了议谷,那線程就繼續(xù)執(zhí)行炉爆,否則它就必須等待知道收到可以安全離開Safe Region的信號(hào)為止。
4. 垃圾收集器
4.1. Serial收集器
- 是一個(gè)單線程垃圾收集器卧晓,它只會(huì)使用一個(gè)CPU或者一條收集線程去完成垃圾收集工作芬首。
- 它在進(jìn)行垃圾收集時(shí),必須暫停其他所有的工作線程逼裆,知道收集結(jié)束郁稍。
- 適用于Client。
- 新生代使用復(fù)制算法胜宇,暫停所有線程耀怜;老年代使用標(biāo)記-整理算法,暫停所有線程桐愉。
4.2. ParNew收集器
Serial的多線程版本封寞,除了使用多條線程進(jìn)行垃圾收集之外,其余行為包括Serial收集器的可用參數(shù)仅财、收集算法、Stop The World碗淌、對(duì)象分配規(guī)則盏求、回收策略都與Serial收集器完全一樣
-
除了Serial收集器外抖锥,目前只有它能與CMS收集器配合工作。
ParNew收集器也是使用
-XX:+UseConcMarkSweepGC
選項(xiàng)后的默認(rèn)新生代收集器碎罚,也可以使用-XX:+UseParNewGC
選項(xiàng)強(qiáng)制指定磅废。ParNew在單核下不會(huì)比Serial收集器效果好
可以使用-XX:ParallelGCThreads參數(shù)來限制垃圾收集的線程數(shù)。
4.3. Parallel Scavenge收集器
他是一個(gè)新生代處理器荆烈,也是使用復(fù)制算法的收集器拯勉,也是并行的多線程處理器。
-
Parallel Scavenge收集器的目的是達(dá)到一個(gè)可控制的吞吐量憔购。
吞吐量 = 運(yùn)行用戶代碼的時(shí)間 / (運(yùn)行用戶代碼時(shí)間 + 垃圾收集時(shí)間)
-
它提供了兩個(gè)參數(shù)控制吞吐量:控制最大垃圾收集停頓的時(shí)間-XX:MaxGCPauseMillis宫峦,直接設(shè)置吞吐量大小-XX:GCTimeRatio
-XX:MaxGCPauseMillis:允許的值是一個(gè)大于0的毫秒數(shù),收集器將盡可能地保證內(nèi)存回收花費(fèi)不超過設(shè)定值玫鸟,GC停頓時(shí)間縮短是以犧牲吞吐量和新生代空間來換取的导绷。
-XX:GCTimeRatio:參數(shù)的值是大于0小于100的整數(shù),就是垃圾收集時(shí)間占總時(shí)間的比率屎飘,如:19妥曲,允許最大的時(shí)間就是1/(1+19);99钦购,允許最大的時(shí)間就是1/(1+99)
-
Parallel Scavenge參數(shù):-XX:UseAdaptiveSizePolicy
-XX:UseAdaptiveSizePolicy 打開這個(gè)參數(shù)檐盟,就不需要手工指定新生代大小、Eden與Survivor區(qū)的比列押桃、晉升老年代對(duì)象大小等細(xì)節(jié)參數(shù)葵萎。虛擬機(jī)會(huì)根據(jù)當(dāng)前系統(tǒng)的運(yùn)行情況收集性能監(jiān)控,動(dòng)態(tài)調(diào)整這些參數(shù)以提供最適合的停頓時(shí)間和最大吞吐量怨规,這種調(diào)節(jié)方式稱為GC自適應(yīng)調(diào)整策略(GC Ergonomics)
4.4. Serial Old收集器
- Serial收集器的老年代版陌宿,單線程,使用“標(biāo)記-整理”算法
- 作為CMS收集器的后背元波丰,在并發(fā)收集發(fā)生Concurrent Mode Failure時(shí)使用壳坪。
4.5. Parallel Old收集器
- 是Parallel Scavenge收集器的老年代版本。使用多線程和“標(biāo)記-整理”算法掰烟。
- 在注重吞吐量以及CPU資源敏感的場(chǎng)景爽蝴,可以優(yōu)先考慮Paralled Scavenge+Parallel Old收集器。
4.6 CMS(Concurrent Mark Swap) 收集器
CMS(Concurrent Mark Sweep)收集器是一種以獲取最短回收停頓時(shí)間為目標(biāo)的收集器纫骑。適用于互聯(lián)網(wǎng)站和B/S系統(tǒng)的服務(wù)端上蝎亚。并發(fā)收集、低停頓先馆。
-
CMS收集器是基于“標(biāo)記-清除”算法實(shí)現(xiàn)发框,過程分為4步:
初始標(biāo)記(CMS initial mark):僅僅是標(biāo)記一下GC Roots能直接關(guān)聯(lián)到的對(duì)象,速度很快煤墙。
并發(fā)標(biāo)記(CMS concurrent mark):進(jìn)行GC Roots Tracing的過程梅惯。
重新標(biāo)記(CMS remark):是為了修正并發(fā)標(biāo)記期間因用戶程序繼續(xù)運(yùn)作而導(dǎo)致標(biāo)記產(chǎn)生變動(dòng)的那一部分對(duì)象的標(biāo)記記錄宪拥。停頓時(shí)間一般比初始標(biāo)記更長(zhǎng),遠(yuǎn)比并發(fā)標(biāo)記時(shí)間短铣减。
并發(fā)清除(CMS concurrent sweep)
其中初始標(biāo)記她君、重新標(biāo)記這兩個(gè)步驟仍然需要“stop the world”
-
CMS的幾個(gè)缺點(diǎn):
對(duì)CPU資源非常敏感:它雖然不會(huì)導(dǎo)致用戶線程停頓,但是啟用線程葫哗,消耗CPU運(yùn)算資源缔刹,會(huì)導(dǎo)致引用程序變慢,總吞吐量降低劣针。CMS的默認(rèn)啟用回收的線程數(shù)是(CPU數(shù)量 + 3)/ 4.也就是說校镐,CPU越少,占用性能越多酿秸,對(duì)程序的影響就越大灭翔。為了應(yīng)對(duì)這種狀況,JVM提供了“增量式并發(fā)收集器”(Incremental Concurrent Mark Swap/i-CMS)辣苏,使用搶占式來模擬多任務(wù)機(jī)制肝箱,在并發(fā)標(biāo)記和清理的時(shí)候讓GC線程、用戶線程交替運(yùn)行稀蟋。盡量減少GC線程獨(dú)占資源的時(shí)間煌张,這樣整個(gè)垃圾收集時(shí)間過程會(huì)更長(zhǎng),但是對(duì)用戶的影響就顯得更少退客。
CMS無法處理“浮動(dòng)垃圾(Floating Garbage)”骏融,可能出現(xiàn)“Concurrent Mode Failure”失敗而導(dǎo)致另一次Full GC的產(chǎn)生。浮動(dòng)垃圾即在CMS并發(fā)清理時(shí)用戶線程還在運(yùn)行產(chǎn)生的心垃圾萌狂,這部分垃圾出現(xiàn)在標(biāo)記過后档玻,無法再當(dāng)次處理。正因?yàn)橛脩艟€程還在運(yùn)行茫藏,就需要預(yù)留一部分內(nèi)存給用戶線程使用误趴,所以CMS可以設(shè)置觸發(fā)百分比:
-XX:CMSInitiatingOccupancyFraction=70
和-XX:+UseCMSInitiatingOccupancyOnly
前者設(shè)置百分比,后者設(shè)置只用設(shè)置的百分比务傲,不讓JVM自動(dòng)調(diào)整凉当,如果不設(shè)置后面的,第一次會(huì)使用70售葡,隨后就會(huì)隨JVM自動(dòng)調(diào)整了看杭。如果CMS運(yùn)行時(shí),預(yù)留內(nèi)存無法滿足需要挟伙,就會(huì)出現(xiàn)“Concurrent Mode Failure”楼雹,這是JVM就會(huì)啟用后后備方案使用Serial Old來重新進(jìn)行老年代收集。所以比例不能設(shè)置太高,不然就會(huì)容易引起Concurrent Mode Failure烘豹,性能反而降低瓜贾。CMS是基于“標(biāo)記-清除”算法實(shí)現(xiàn)的,所以收集結(jié)束后會(huì)有大量的空間碎片產(chǎn)生携悯。雖然空間很多,但是無法給大對(duì)象找到一片連續(xù)的空間筷笨,從而不得不觸發(fā)一次Full GC。為了解決這個(gè)問題,CMS提供了一個(gè)-XX:+UseCMSCompactAtFullCollection,用于在CMS要進(jìn)行Full GC的時(shí)候開啟內(nèi)存碎片合并整理炒嘲,這個(gè)過程無法并發(fā)進(jìn)行越平,空間碎片問題解決,但是停頓時(shí)間變長(zhǎng)仰禀。CMS還有一個(gè)-XX:CMSFullGCsBeforeCompaction照雁,這個(gè)參數(shù)是用于設(shè)置執(zhí)行多少次不壓縮的Full GC后,跟著來一次帶壓縮的答恶,為0是表示每次進(jìn)入Full GC 都?jí)嚎s饺蚊。
4.7 G1(Garbage-First)收集器
-
G1是一款面向服務(wù)端應(yīng)用的垃圾收集器。HotSpot開發(fā)來替代CMS的悬嗓,特點(diǎn)如下:
并行與并發(fā): G1能充分利用多CPU污呼、多核環(huán)境下的硬件優(yōu)勢(shì),使用多個(gè)CPU來縮短Stop-The-World停頓的時(shí)間包竹,部分其他收集器原本需要停頓Java線程執(zhí)行的GC動(dòng)作燕酷,G1收集器仍然可以通過并發(fā)的方式讓Java程序繼續(xù)執(zhí)行。
分代收集: 分代概念在G1中依然得以保留周瞎。G1可以不需要其他收集器配合就能獨(dú)立管理整個(gè)GC堆苗缩,它能夠采用不同的方式去處理新創(chuàng)建的對(duì)象和已經(jīng)存活了一段時(shí)間、熬過多次GC的舊對(duì)象以獲取更好的收集效果声诸。G1可以自己管理新生代和老年代酱讶。
可預(yù)測(cè)的停頓: 降低停頓時(shí)間是G1和CMS共同的關(guān)注點(diǎn),G1除了追求低停頓外双絮,還建立可預(yù)測(cè)的停頓時(shí)間模型浴麻,能讓使用者明確指定在一個(gè)長(zhǎng)度為M毫秒的時(shí)間片段內(nèi),消耗在垃圾收集上的時(shí)間不得超過N毫秒囤攀,這幾乎已經(jīng)是實(shí)時(shí)Java(RTSJ)的垃圾收集器的特征了软免。G1可以有計(jì)劃的避免在整個(gè)JVM堆中進(jìn)行垃圾收集,可以對(duì)每個(gè)region里的回收對(duì)象價(jià)值(回收該區(qū)域的時(shí)間消耗和能得到的內(nèi)存比值)進(jìn)行分析焚挠,在最后篩選回收階段膏萧,對(duì)每個(gè)region里的回收對(duì)象價(jià)值(回收該區(qū)域的時(shí)間消耗和能得到的內(nèi)存比值)最后進(jìn)行排序,用戶可以自定義停頓時(shí)間,那么G1就可以對(duì)部分的region進(jìn)行回收榛泛!這使得停頓時(shí)間是用戶自己可以控制的蝌蹂!
空間整合,沒有內(nèi)存碎片產(chǎn)生:由于G1使用了獨(dú)立區(qū)域(Region)概念曹锨,G1從整體來看是基于“標(biāo)記-整理”算法實(shí)現(xiàn)收集孤个,從局部(兩個(gè)Region)上來看是基于“復(fù)制”算法實(shí)現(xiàn)的,但無論如何沛简,這兩種算法都意味著G1運(yùn)作期間不會(huì)產(chǎn)生內(nèi)存空間碎片齐鲤。
在G1之前的其他收集器進(jìn)行收集的范圍都是整個(gè)新生代或者老年代,而G1不再是這樣椒楣。使用G1收集器時(shí)给郊,Java堆的內(nèi)存布局就與其他收集器有很大差別,它將整個(gè)Java堆劃分為多個(gè)大小相等的獨(dú)立區(qū)域(Region)捧灰,雖然還保留有新生代和老年代的概念淆九,但新生代和老年代不再是物理隔離的了,它們都是一部分Region(不需要連續(xù))的集合毛俏。
G1收集器之所以能建立可預(yù)測(cè)的停頓時(shí)間模型炭庙,是因?yàn)樗梢杂杏?jì)劃地避免在整個(gè)Java堆中進(jìn)行全區(qū)域的垃圾收集。G1跟蹤各個(gè)Region里面的垃圾堆積的價(jià)值大信《丁(回收所獲得的空間大小以及回收所需時(shí)間的經(jīng)驗(yàn)值)煤搜,在后臺(tái)維護(hù)一個(gè)優(yōu)先列表,每次根據(jù)允許的收集時(shí)間唧席,優(yōu)先回收價(jià)值最大的Region(這也就是Garbage-First名稱的來由)擦盾。這種使用Region劃分內(nèi)存空間以及有優(yōu)先級(jí)的區(qū)域回收方式,保證了G1收集器在有限的時(shí)間內(nèi)可以獲取盡可能高的收集效率淌哟。
G1收集器中迹卢,Region之間的對(duì)象引用以及其他收集器中的新生代與老年代之間的對(duì)象引用,虛擬機(jī)都是使用Remembered Set來避免全堆掃描的徒仓。G1中每個(gè)Region都有一個(gè)與之對(duì)應(yīng)的Remembered Set腐碱,虛擬機(jī)發(fā)現(xiàn)程序在對(duì)Reference類型的數(shù)據(jù)進(jìn)行寫操作時(shí),會(huì)產(chǎn)生一個(gè)Write Barrier暫時(shí)中斷寫操作掉弛,檢查Reference引用的對(duì)象是否處于不同的Region之中(在分代的例子中就是檢查是否老年代中的對(duì)象引用了新生代中的對(duì)象)症见,如果是,便通過CardTable把相關(guān)引用信息記錄到被引用對(duì)象所屬的Region的Remembered Set之中殃饿。當(dāng)進(jìn)行內(nèi)存回收時(shí)谋作,在GC根節(jié)點(diǎn)的枚舉范圍中加入Remembered Set即可保證不對(duì)全堆掃描也不會(huì)有遺漏。
-
不計(jì)算維護(hù)Remembered Set的操作乎芳,G1收集器的運(yùn)作大致可劃分為以下幾個(gè)步驟:
初始標(biāo)記(Initial Marking)
并發(fā)標(biāo)記(Concurrent Marking)
最終標(biāo)記(Final Marking)
篩選回收(Live Data Counting and Evacuation)
關(guān)于我
- 坐標(biāo)杭州遵蚜,普通本科在讀帖池,計(jì)算機(jī)科學(xué)與技術(shù)專業(yè),20年畢業(yè)吭净,目前處于實(shí)習(xí)階段睡汹。
- 主要做Java開發(fā),會(huì)寫點(diǎn)Golang寂殉、Shell囚巴。對(duì)微服務(wù)、大數(shù)據(jù)比較感興趣不撑,預(yù)備做這個(gè)方向文兢。
- 目前處于菜鳥階段,各位大佬輕噴焕檬,小弟正在瘋狂學(xué)習(xí)。
- 歡迎大家和我交流鴨0谋谩J涤蕖!