1偿警、背景
G1(Garbage First Collector 垃圾優(yōu)先的收集器)负间,說是一種全新的相艇,其實G1垃圾收集器已經(jīng)出現(xiàn)了N多年了颖杏,只是從發(fā)展到成熟是需要經(jīng)歷一定的過程,oracle官方計劃在jdk9中將G1變成默認的垃圾收集器坛芽,以替代CMS输玷, 可見G1肯定有它獨特的地方,它跟我們之前所學的各種垃圾底層是完全不一樣的靡馁,比如最明顯的不同是以前的分代收集方式是將堆劃分為新生代、老年代兩個區(qū)域机久,而新生代又劃分為Eden和兩個Survivor臭墨,也就是從物理的結(jié)構(gòu)就明確的做了區(qū)域劃分,但是1旄恰k食凇!G1它依據(jù)的物理形態(tài)跟我們之前所接觸的垃圾收集器完全不一樣了侠畔,也就是明顯會感覺到G1里面的堆內(nèi)存沒有明顯的區(qū)域劃分
2结缚、吞吐量:
吞吐量關(guān)注的是,在一個指定的時間內(nèi)软棺,最大化一個應(yīng)用的工作量红竭。
如下方式來衡量一個系統(tǒng)吞吐量的好壞:
1、在一個小時內(nèi)同一個事務(wù)(或者任務(wù)喘落、請求)完成的次數(shù)(tps茵宪,實際中還會經(jīng)常見qps,每秒查詢率QPS是對一個特定的查詢服務(wù)器在規(guī)定時間內(nèi)所處理流量多少的衡量標準)瘦棋。
2稀火、數(shù)據(jù)庫一小時可以完成多少次查詢。對于關(guān)注吞吐量的系統(tǒng)赌朋,卡頓是可以接受的凰狞,因為這個系統(tǒng)關(guān)注長時間的大量任務(wù)的執(zhí)行能力篇裁,單次快速的響應(yīng)并不值得考慮。
3赡若、響應(yīng)能力:
- 響應(yīng)能力指一個程序或者系統(tǒng)對請求是否能夠及時響應(yīng)达布,比如:
1、一個桌面UI能多快地響應(yīng)一個事件斩熊。
2往枣、一個網(wǎng)站能夠多快返回一個頁面請求。
3粉渠、數(shù)據(jù)庫能夠多快返回查詢的數(shù)據(jù)分冈。 - 對于這類對響應(yīng)能力敏感的場景,長時間的停頓是無法接受的霸株。
以上是用來評價一個系統(tǒng)的兩個很重要的指標雕沉,介紹這兩個指標的原因是因為G1就是用來解決這樣的問題而應(yīng)運而生的。
4去件、G1垃圾回收器
- g1收集器是一個面向服務(wù)端的垃圾收集器坡椒,適用于多核處理器、大內(nèi)存容量的服務(wù)端系統(tǒng)尤溜。
- 它滿足短時間gc停頓的同時達到一個較高的吞吐量倔叼。
- JDK7以上版本適用【通過配置JVM的參數(shù)來指定既可】。
以上可以看到G1在吞吐量和響應(yīng)能力上都進行了兼顧宫莱。
5丈攒、G1收集器的設(shè)計目標:
(延遲可控的情況下獲得盡可能高的吞吐量)
- 與應(yīng)用線程同時工作,幾乎【注意措辭】不需要stop the world(與CMS類似)授霸;
- 整理剩余空間巡验,不產(chǎn)生內(nèi)存碎片(CMS只能在Full GC時,用stop the world整理內(nèi)存碎片)碘耳。
- GC停頓更加可控显设;【要是CMS運行期間預留的內(nèi)存無法滿足程序需要時,虛擬機將啟動后備預案:臨時啟用Serial Old收集器來重新進行老年代的垃圾收集辛辨,這樣停頓時間就很長了捕捂。同時對于CMS來說如果出現(xiàn)了Full GC時,則會對新生代和老年代的堆內(nèi)存進行完整的整理愉阎,停頓時間就不可控了】
- 不犧牲系統(tǒng)的吞吐量绞蹦;
- gc不要求額外的內(nèi)存空間(CMS需要預留空間存儲浮動垃圾【這個在學習CMS中已經(jīng)闡述過了,其實就是CMS回收的過程跟用戶線程是并發(fā)進行的榜旦,所在在標記或者清除的同時對象的引用還會被改變幽七,使得原來對象本來不是垃圾,當CMS清理時該對象已經(jīng)變成了垃圾了溅呢,但是CMS認為它還不是垃圾澡屡,所以該對象的清除工作就會放到下一次了猿挚,所以將這種對象則稱之為浮動垃圾】)
6、G1內(nèi)存模型
1驶鹉、G1堆結(jié)構(gòu)
(1)分區(qū) Region
G1 采用了分區(qū)(Region)的思路绩蜻,堆被劃分為一個個相等的不連續(xù)的內(nèi)存區(qū)域(regions),每個regions都有一個分代的角色:eden室埋、survivor办绝、old。對每個角色的數(shù)量并沒有強制的限定姚淆,也就是說對每種分代內(nèi)存的大小孕蝉,可以動態(tài)變化。每個分區(qū)也不會確定地為某個代服務(wù)腌逢,可以按需在年輕代和老年代之間切換降淮。啟動時可以通過參數(shù) -XX:G1HeapRegionSize=n 可指定分區(qū)大小(1MB~32MB搏讶,且必須是2的冪)佳鳖,默認將整堆劃分為2048個分區(qū)。
(2)卡片 Card
在每個分區(qū)內(nèi)部又被分成了若干個大小為512 Byte 卡片(Card)媒惕,標識堆內(nèi)存最小可用粒度所有分區(qū)的卡片將會記錄在全局卡片表(Global Card Table)中系吩,分配的對象會占用物理上連續(xù)的若干個卡片,當查找對分區(qū)內(nèi)對象的引用時便可通過記錄卡片來查找該引用對象(見 RSet)妒蔚。每次對內(nèi)存的回收淑玫,都是對指定分區(qū)的卡片進行處理。默認情況下面睛,每個卡都未被引用。當一個地址空間被引用時尊搬,這個地址空間對應(yīng)的數(shù)組索引的值被標記為“0”叁鉴,既標記為被引用,此外RSet也將這個數(shù)組下標記錄下來佛寿。一般情況下幌墓,這個RSet其實是一個Hash Table,key是當前Region的起始地址冀泻,Value是一個集合常侣,里面的元素是Card Table的Index。
(3)已記憶集合 Remember Set(RSet)
在串行和并行收集器中弹渔,GC 通過整堆掃描胳施,來確定對象是否處于可達路徑中。然而 G1 為了避免 STW 式的整堆掃描肢专,在每個分區(qū)記錄了一個已記憶集合(RSet)舞肆,內(nèi)部類似一個反向指針焦辅,記錄引用分區(qū)內(nèi)對象的卡片索引。當要回收該分區(qū)時椿胯,通過掃描分區(qū)的 RSet筷登,來確定引用本分區(qū)內(nèi)的對象是否存活,進而確定本分區(qū)內(nèi)的對象存活情況哩盲。
事實上前方,并非所有的引用都需要記錄在 RSet 中,引用源自本分區(qū)的對象廉油,當然不用落入 RSet 中惠险;同時,G1 GC 每次都會對年輕代進行整體收集娱两,因此引用源自年輕代的對象莺匠,也不需要在 RSet 中記錄。最后只有老年代的分區(qū)可能會有 RSet 記錄十兢,這些分區(qū)稱為擁有 RSet 分區(qū)(an RSet’s owning region)趣竣。
(4)Humongous區(qū)域
在G1中,還有一種特殊的區(qū)域旱物,叫Humongous區(qū)域遥缕。如果一個對象占用的空間達到或者超過了分區(qū)容量的50%以上,G1收集器就認為這是一個巨型對象宵呛。這些巨型對象单匣,默認直接會被分配在老年代,但是如果它是一個短期存在的巨型對象宝穗,就會對垃圾收集器造成負面影響户秤,為了解決這個問題,G1劃分 Humongous區(qū)域逮矛,它專門用來存放巨型對象鸡号。如果一個H區(qū)域裝不下一個巨型對象,那么G1會尋找連續(xù)的H分區(qū)來存儲须鼎。為了能找到連續(xù)的H區(qū)鲸伴,有時候不得不啟動Full GC
2、收集集合(CSet)
收集集合(CSet)代表每次 GC 暫停時回收的一系列目標分區(qū)晋控。在任意一次收集暫停中汞窗,CSet 所有分區(qū)都會被釋放,內(nèi)部存活的對象都會被轉(zhuǎn)移到分配的空閑分區(qū)中赡译。因此無論是年輕代收集仲吏,還是混合收集,工作的機制都是一致的。
①:年輕代收集 CSet 只容納年輕代分區(qū)蜘矢,
②:混合收集會通過某種算法狂男,在老年代候選回收分區(qū)中,篩選出回收收益最高的分區(qū)添加到 CSet 中品腹。
該算法是:G1跟蹤各個Region里面的垃圾堆積的價值大嗅场(回收所獲得的空間大小以及回收所需要時間的經(jīng)驗值),在后臺維護一個優(yōu)先列表舞吭,每次根據(jù)允許的收集時間泡垃,優(yōu)先回收價值最大的Region
年輕代收集集合 CSet of Young Collection(詳細版)
應(yīng)用線程不斷活動后,年輕代空間會被逐漸填滿羡鸥。當 JVM 分配對象到 Eden 區(qū)域失斆镅ā(Eden 區(qū)已滿)時,便會觸發(fā)一次 STW 式的年輕代收集惧浴。在年輕代收集中存和,Eden 分區(qū)存活的對象將被拷貝到 Survivor 分區(qū);原有 Survivor 分區(qū)存活的對象衷旅,將根據(jù)任期閾值(tenuring threshold)分別晉升到 PLAB 中捐腿,新的 survivor 分區(qū)和老年代分區(qū)。而原有的年輕代分區(qū)將被整體回收掉柿顶。
同時茄袖,年輕代收集還負責維護對象的年齡(存活次數(shù)),輔助判斷老化(tenuring)對象晉升的時候是到 Survivor 分區(qū)還是到老年代分區(qū)嘁锯。年輕代收集首先先將晉升對象尺寸總和宪祥、對象年齡信息維護到年齡表中,再根據(jù)年齡表家乘、Survivor 尺寸蝗羊、Survivor 填充容量 -XX:TargetSurvivorRatio(默認50%)、最大任期閾值 -XX:MaxTenuringThreshold(默認15)仁锯,計算出一個恰當?shù)娜纹陂撝抵饨唬彩浅^任期閾值的對象都會被晉升到老年代。
混合收集集合 CSet of Mixed Collection
年輕代收集不斷活動后扑馁,老年代的空間也會被逐漸填充。當老年代占用空間超過整堆比 IHOP 閾值 -XX:InitiatingHeapOccupancyPercent(默認45%)時凉驻,G1 就會啟動一次混合垃圾收集周期腻要。為了滿足暫停目標,G1 可能不能一口氣將所有的候選分區(qū)收集掉涝登,因此 G1 可能會產(chǎn)生連續(xù)多次的混合收集與應(yīng)用線程交替執(zhí)行雄家,每次 STW 的混合收集與年輕代收集過程相類似。
3胀滚、可預測的停頓模型
G1使用了gc停頓可預測的模型趟济,來滿足用戶設(shè)定的gc停頓時間乱投,根據(jù)用戶設(shè)定的目標時間,G1會自動地選擇哪些region要清除顷编,一次清除多少個region戚炫。
這是G1相對于CMS的另一個大優(yōu)勢,G1除了追求低停頓外媳纬,還能建立可預測的停頓時間模型双肤,能讓使用者明確指定在一個長度為M毫秒的時間片段內(nèi),消耗在垃圾收集上的時間不得超過N毫秒
- 由于分區(qū)的原因钮惠,G1可以只選部分區(qū)域進行內(nèi)存回收茅糜,這樣縮小了回收的范圍,因此對于全局停頓情況的發(fā)生也能得到較好的控制
- G1跟蹤各個Region里面的垃圾堆積的價值大兴赝臁(回收所獲得的空間大小以及回收所需要時間的經(jīng)驗值)蔑赘,在后臺維護一個優(yōu)先列表,每次根據(jù)允許的收集時間预明,優(yōu)先回收價值最大的Region缩赛。保證了G1收集器在有限的時間內(nèi)可以獲取盡可能高的收集效率。
- 相比于CMS GC贮庞,G1未能做到CMS在最好情況下的延時停頓峦筒,但是最長情況要好很多
- 停頓時間的設(shè)置并不是越短越好,設(shè)置的時間越短意味著每次收集的Cset越小窗慎,導致垃圾逐步積累變多物喷,最終不得不退化成Full GC(Serial GC),停頓時間設(shè)置過長遮斥,那么會導致每次都會產(chǎn)生長時間的停頓個峦失,影響了程序?qū)ν獾捻憫?yīng)時間
7、G1垃圾回收器的缺點
1术吗、相對于CMS尉辑,G1還不具備全方位、壓倒性的優(yōu)勢较屿,比如在用戶程序運行過程中隧魄,G1無論是為了垃圾收集產(chǎn)生的內(nèi)存占用還是程序運行時的額外執(zhí)行負載都要比CMS要高
2、從經(jīng)驗上來說隘蝎,在小內(nèi)存應(yīng)用上CMS的表現(xiàn)大概率會優(yōu)于G1购啄,而G1在大內(nèi)存應(yīng)用則發(fā)揮其優(yōu)勢,平衡點6 ~ 8GB之間
8嘱么、G1垃圾回收過程
1狮含、年輕代GC(Young GC)
年輕代垃圾回收只會回收Eden區(qū)和Survivor區(qū)。年輕代也使用了分區(qū)機制主要是因為便于代大小的調(diào)整
年輕代回收時,首先G1停止應(yīng)用程序的執(zhí)行(Stop - The - World)几迄,G1創(chuàng)建回收集(CSet)蔚龙,對于YGC來說,整個年輕代(Eden區(qū) + Survivor區(qū))都是CSet
然后開始如下回收過程(并行操作映胁,多個收集器的線程同時工作木羹,但是用戶線程處于等待狀態(tài)。)
階段1:根掃描
GC Roots包括
(1). 虛擬機棧(棧幀中的局部變量區(qū)屿愚,也叫做局部變量表)中引用的對象汇跨。
(2). 方法區(qū)中的類靜態(tài)屬性引用的對象。
(3). 方法區(qū)中常量引用的對象妆距。
(4). 本地方法棧中JNI(Native方法)引用的對象穷遂。
階段2:更新RSet
處理dirty card隊列更新RS(更新完后,RSet可以準確的反映老年代對所在的內(nèi)存分段中對象的引用)
對于應(yīng)用程序的引用賦值語句Object.field = object娱据,JVM會在之前和之后執(zhí)行特殊的操作以在dirty card queue中入隊一個保存了對象引用信息的card蚪黑。在年輕代回收的時候,G1會對DIrty Card Queue中所有的card進行處理中剩,以更新RSet忌穿,保證RSet實時準確的反映引用關(guān)系
那為什么不在引用賦值語句處直接更新RSet呢?這是為了性能的需要结啼,RSet的處理需要線程同步掠剑,開銷會很大,使用隊列性能會好很多
階段3:處理RSet
識別被老年代對象指向的Eden中的對象郊愧,這些被指向的Eden中的對象被認為存活的對象
階段4:復制對象
拷貝存活的對象到survivor/old區(qū)域朴译。① Survivor區(qū)內(nèi)存中存活的對象如果年齡未達到閾值,年齡會加1属铁,達到閾值會被賦值到Old區(qū)眠寿。 ② 如果Survivor空間不夠,Eden空間的部分數(shù)據(jù)會直接晉升到老年代空間
階段5:處理引用隊列
軟引用焦蘑、弱引用盯拱、虛引用處理
2、并發(fā)標記過程(Concurrent Marking)
1例嘱、初始標記(inital mark狡逢,STW):它標記了從GC Root開始直接可達的對象,并且會觸發(fā)一次年輕代的GC
2拼卵、根區(qū)域掃描(Root Region Sacnning):觸發(fā)的年輕代GC完成后奢浑,所有新復制到 Survivor 分區(qū)(根區(qū)域)的對象,都需要被掃描并標記成根间学,G1 GC掃描Survivor取直接可達的老年代區(qū)域?qū)ο螅擞洷灰玫膶ο蟆_@個過程必須在young GC之前完成
3低葫、并發(fā)標記(Concurrent Marking):這個階段從GC Root開始對heap中的對象進行標記详羡,標記線程與應(yīng)用程序線程并發(fā)執(zhí)行,并且收集各個Region的存活對象信息嘿悬。
4实柠、重新標記(Remark,STW):由于應(yīng)用程序持續(xù)進行善涨,需要修正上一次的標記結(jié)果窒盐,SATB算法
5、獨占清理(Exclusive Cleanup钢拧,STW):計算各個區(qū)域的存活對象和GC回收比例蟹漓,并進行排序,識別可以混合回收的區(qū)域源内。為混合回收做鋪墊葡粒,是STW的。這個階段不會實際上做垃圾的收集
6膜钓、并發(fā)清理(Concurrent Cleanup):清除空Region(沒有存活對象的)嗽交,加入到free list。
3颂斜、混合回收(Mixed GC)
在并發(fā)標記過程后進行拷貝存活對象