吞吐量
垃圾回收算法(6 個(gè)字太長(zhǎng)了哥牍,以下簡(jiǎn)稱 GC)算是對(duì)程序完成它想做的事情的一種輔助毕泌,并不是程序的主要目的(廢話)。所以 GC 占用的時(shí)間越少越好嗅辣,程序花在正事上面的時(shí)間越多越好撼泛。
這個(gè)指標(biāo)其實(shí)很好理解。舉個(gè)例子吧澡谭,標(biāo)記清除算法要遍歷兩次愿题,第一次遍歷所有活躍的對(duì)象,將它們標(biāo)記為“不是垃圾”。第二次遍歷所有的對(duì)象潘酗,將沒(méi)有被標(biāo)記的垃圾回收掉杆兵。復(fù)制收集算法只需要遍歷一次,將活躍的對(duì)象從內(nèi)存的一般復(fù)制到另一半仔夺。所以從這個(gè)指標(biāo)的角度講琐脏,復(fù)制收集算法完爆標(biāo)記清除。
但實(shí)際上缸兔,這個(gè)指標(biāo)是不能“靜態(tài)衡量”的日裙。依然是上面兩種算法,標(biāo)記清除遍歷的時(shí)候速度很快惰蜜,只要寫(xiě)一個(gè)標(biāo)記就可以了昂拂。而復(fù)制收集算法要有 copy 操作。隨著堆中活動(dòng)對(duì)象的增加抛猖,甚至?xí)霈F(xiàn)復(fù)制收集吞吐量小于標(biāo)記清除的情況格侯。
內(nèi)存使用率
這個(gè)指標(biāo)也比較好理解,GC 算法需要一些標(biāo)記樟结,但是如果算法本身所使用的內(nèi)存占得很多养交,就得不償失了。這個(gè)算法本身的目的就是回收內(nèi)存瓢宦,本身卻占用了很多內(nèi)存碎连,聽(tīng)起來(lái)就不合理。
其實(shí)驮履,從算法的角度講鱼辙,內(nèi)存是空間,吞吐量是時(shí)間玫镐。算法上有“用空間換時(shí)間”的策略倒戏,自然 GC 也會(huì)有。這是一種 Trade off恐似,很多情況不可兼得杜跷。
拿引用計(jì)數(shù)來(lái)說(shuō),用幾個(gè)位來(lái)表示引用計(jì)數(shù)是門(mén)學(xué)問(wèn)矫夷。簡(jiǎn)單的話葛闷,占用 8 個(gè)位表示,那每個(gè)對(duì)象 1byte 就沒(méi)有了双藕。假設(shè)是占用 2 個(gè)字節(jié)的對(duì)象淑趾,那么內(nèi)存占用就擴(kuò)大了整整 1.5 倍。 而大多數(shù)對(duì)象僅僅會(huì)被引用 1 次而已忧陪。所以引用計(jì)數(shù)方法就發(fā)展出一些優(yōu)化措施扣泊,減少引用計(jì)數(shù)占用的內(nèi)存近范,配合其他算法來(lái)處理計(jì)數(shù)器溢出的問(wèn)題。有一種極端的方式是只使用 1 位來(lái)計(jì)數(shù)(倒不如說(shuō)這是一種標(biāo)記了)延蟹。
最大暫停時(shí)間
這個(gè)指標(biāo)和“吞吐量”看起來(lái)有些像评矩,GC 算法速度越快,時(shí)間就越小等孵。但是吞吐量指的是總體的速度稚照,最大暫停時(shí)間指的是 GC 算法執(zhí)行的時(shí)候蹂空,程序在等待 GC 完成的最大時(shí)間俯萌。這段時(shí)間由于 GC 的運(yùn)行程序無(wú)法做其他的事情。
為什么這個(gè)指標(biāo)會(huì)重要呢上枕?有些程序可能可以忍受吞吐量不高咐熙,但是實(shí)時(shí)性要求很強(qiáng)的。比如說(shuō)辨萍,A 算法每分鐘暫停 1 次棋恼,一次暫停 1 秒,一小時(shí)一共暫停 60s锈玉。另一個(gè) B 算法每小時(shí)暫停 1 次爪飘,一次暫停 30s±常可想而知师崎,如果是用戶程序暫停時(shí)間長(zhǎng)是體驗(yàn)很糟糕的,另外比如機(jī)器人控制程序椅棺,邁開(kāi)一只腿這時(shí)候到了暫停時(shí)間犁罩,機(jī)器人就摔倒了。
引用計(jì)數(shù)的最大暫停時(shí)間是最好的两疚,因?yàn)閷?duì)象的引用到 0 的時(shí)候立即會(huì)回收床估,這個(gè)過(guò)程不需要暫停程序。而復(fù)制算法和標(biāo)記清除算法需要在無(wú)法申請(qǐng)出更多內(nèi)存的時(shí)候诱渤,暫停程序丐巫,開(kāi)始清除階段/復(fù)制階段。
連續(xù)性(緩存友好程度)
我們知道勺美,越快的存儲(chǔ)價(jià)格就越高递胧。CPU 寄存器速度最快,但是只有幾個(gè)寄存器励烦。高速緩存非澄阶牛快,但是極其昂貴坛掠。然后是內(nèi)存赊锚、硬盤(pán)等治筒。
如果程序在執(zhí)行的時(shí)候緩存命中率高,那么運(yùn)行效率就會(huì)高舷蒲。
在這篇文章中耸袜,我們可以將程序粗略的分成兩部分:GC 運(yùn)行的部分和程序運(yùn)行的部分。如果 GC 運(yùn)行的時(shí)候需要頻繁尋找對(duì)象牲平,然后對(duì)象的引用又在很遠(yuǎn)的地方堤框,那么緩存命中率就會(huì)很低;另一方面說(shuō)纵柿,如果 GC 算法將程序的對(duì)象變得很離散蜈抓,那么程序在運(yùn)行的時(shí)候,互相引用的對(duì)象離得很遠(yuǎn)昂儒,效率就會(huì)很低沟使。
標(biāo)記清除算法會(huì)造成內(nèi)存的碎片,對(duì)緩存不友好渊跋。復(fù)制收集算法由于是拷貝不是垃圾的對(duì)象腊嗡,所以在一次拷貝操作之后,垃圾對(duì)象被釋放拾酝,非垃圾對(duì)象都在一起了燕少,所以命中率會(huì)高。另外上面提到的 1 位引用計(jì)數(shù)算法由于只拷貝指針蒿囤,而不需要去找到對(duì)象客们,所以緩存命令率也會(huì)高。
GC基礎(chǔ)原理
1 GC調(diào)優(yōu)目標(biāo)
大多數(shù)情況下對(duì) Java 程序進(jìn)行GC調(diào)優(yōu), 主要關(guān)注兩個(gè)目標(biāo):響應(yīng)速度蟋软、吞吐量
響應(yīng)速度(Responsiveness)
響應(yīng)速度指程序或系統(tǒng)對(duì)一個(gè)請(qǐng)求的響應(yīng)有多迅速镶摘。比如,用戶訂單查詢響應(yīng)時(shí)間岳守,對(duì)響應(yīng)速度要求很高的系統(tǒng)凄敢,較大的停頓時(shí)間是不可接受的。調(diào)優(yōu)的重點(diǎn)是在短的時(shí)間內(nèi)快速響應(yīng)
吞吐量(Throughput)
吞吐量關(guān)注在一個(gè)特定時(shí)間段內(nèi)應(yīng)用系統(tǒng)的最大工作量湿痢,例如每小時(shí)批處理系統(tǒng)能完成的任務(wù)數(shù)量涝缝,在吞吐量方面優(yōu)化的系統(tǒng),較長(zhǎng)的GC停頓時(shí)間也是可以接受的譬重,因?yàn)楦咄掏铝繎?yīng)用更關(guān)心的是如何盡可能快地完成整個(gè)任務(wù)拒逮,不考慮快速響應(yīng)用戶請(qǐng)求
GC調(diào)優(yōu)中,GC導(dǎo)致的應(yīng)用暫停時(shí)間影響系統(tǒng)響應(yīng)速度臀规,GC處理線程的CPU使用率影響系統(tǒng)吞吐量
2 GC分代收集算法
現(xiàn)代的垃圾收集器基本都是采用分代收集算法滩援,其主要思想: 將Java的堆內(nèi)存邏輯上分成兩塊:新生代、老年代塔嬉,針對(duì)不同存活周期玩徊、不同大小的對(duì)象采取不同的垃圾回收策略
- 新生代(Young Generation)
新生代又叫年輕代租悄,大多數(shù)對(duì)象在新生代中被創(chuàng)建,很多對(duì)象的生命周期很短恩袱。每次新生代的垃圾回收(又稱Young GC泣棋、Minor GC、YGC)后只有少量對(duì)象存活畔塔,所以使用復(fù)制算法潭辈,只需少量的復(fù)制操作成本就可以完成回收.
新生代內(nèi)又分三個(gè)區(qū):一個(gè)Eden區(qū),兩個(gè)Survivor區(qū)(S0澈吨、S1把敢,又稱From Survivor、To Survivor)棚辽,大部分對(duì)象在Eden區(qū)中生成技竟。當(dāng)Eden區(qū)滿時(shí),還存活的對(duì)象將被復(fù)制到兩個(gè)Survivor區(qū)(中的一個(gè))屈藐。當(dāng)這個(gè)Survivor區(qū)滿時(shí),此區(qū)的存活且不滿足晉升到老年代條件的對(duì)象將被復(fù)制到另外一個(gè)Survivor區(qū)熙尉。對(duì)象每經(jīng)歷一次復(fù)制联逻,年齡加1,達(dá)到晉升年齡閾值后检痰,轉(zhuǎn)移到老年代
老年代(Old Generation)
在新生代中經(jīng)歷了N次垃圾回收后仍然存活的對(duì)象包归,就會(huì)被放到老年代,該區(qū)域中對(duì)象存活率高铅歼。老年代的垃圾回收通常使用“標(biāo)記-整理”算法
3 GC事件分類(lèi)
根據(jù)垃圾收集回收的區(qū)域不同公壤,垃圾收集主要通常分為Young GC、Old GC椎椰、Full GC厦幅、Mixed GC
(1) Young GC
新生代內(nèi)存的垃圾收集事件稱為Young GC(又稱Minor GC),當(dāng)JVM無(wú)法為新對(duì)象分配在新生代內(nèi)存空間時(shí)總會(huì)觸發(fā) Young GC慨飘,比如 Eden 區(qū)占滿時(shí)确憨。新對(duì)象分配頻率越高, Young GC 的頻率就越高
Young GC 每次都會(huì)引起全線停頓(Stop-The-World),暫停所有的應(yīng)用線程瓤的,停頓時(shí)間相對(duì)老年代GC的造成的停頓休弃,幾乎可以忽略不計(jì)
Old GC
,只清理老年代空間的GC事件圈膏,只有CMS的并發(fā)收集是這個(gè)模式
Full GC
塔猾,清理整個(gè)堆的GC事件,包括新生代稽坤、老年代丈甸、元空間等
Mixed GC
医增,清理整個(gè)新生代以及部分老年代的GC,只有G1有這個(gè)模式
GC日志分析
GC日志是一個(gè)很重要的工具老虫,它準(zhǔn)確記錄了每一次的GC的執(zhí)行時(shí)間和執(zhí)行結(jié)果叶骨,通過(guò)分析GC日志可以調(diào)優(yōu)堆設(shè)置和GC設(shè)置,或者改進(jìn)應(yīng)用程序的對(duì)象分配模式祈匙,開(kāi)啟的JVM啟動(dòng)參數(shù)如下:
-verbose:gc -XX:+PrintGCDetails -XX:+PrintGCDateStamps -XX:+PrintGCTimeStamps
常見(jiàn)的Young GC忽刽、Full GC日志含義如下:
免費(fèi)的GC日志圖形分析工具推薦下面2個(gè):
5 內(nèi)存分配策略
Java提供的自動(dòng)內(nèi)存管理,可以歸結(jié)為解決了對(duì)象的內(nèi)存分配和回收的問(wèn)題些阅,前面已經(jīng)介紹了內(nèi)存回收伞剑,下面介紹幾條最普遍的內(nèi)存分配策略
對(duì)象優(yōu)先在Eden區(qū)分配
大多數(shù)情況下,對(duì)象在先新生代Eden區(qū)中分配市埋。當(dāng)Eden區(qū)沒(méi)有足夠空間進(jìn)行分配時(shí)黎泣,虛擬機(jī)將發(fā)起一次Young GC
大對(duì)象直接進(jìn)入老年代
JVM提供了一個(gè)對(duì)象大小閾值參數(shù)(-XX:PretenureSizeThreshold,默認(rèn)值為0缤谎,代表不管多大都是先在Eden中分配內(nèi)存)抒倚,大于參數(shù)設(shè)置的閾值值的對(duì)象直接在老年代分配,這樣可以避免對(duì)象在Eden及兩個(gè)Survivor直接發(fā)生大內(nèi)存復(fù)制
長(zhǎng)期存活的對(duì)象將進(jìn)入老年代
對(duì)象每經(jīng)歷一次垃圾回收坷澡,且沒(méi)被回收掉托呕,它的年齡就增加1,大于年齡閾值參數(shù)(-XX:MaxTenuringThreshold频敛,默認(rèn)15)的對(duì)象项郊,將晉升到老年代中
空間分配擔(dān)保
當(dāng)進(jìn)行Young GC之前,JVM需要預(yù)估:老年代是否能夠容納Young GC后新生代晉升到老年代的存活對(duì)象斟赚,以確定是否需要提前觸發(fā)GC回收老年代空間着降,基于空間分配擔(dān)保策略來(lái)計(jì)算:
continueSize:老年代最大可用連續(xù)空間
Young GC之后如果成功(Young GC后晉升對(duì)象能放入老年代),則代表?yè)?dān)保成功汁展,不用再進(jìn)行Full GC鹊碍,提高性能;如果失敗食绿,則會(huì)出現(xiàn)“promotion failed”錯(cuò)誤侈咕,代表?yè)?dān)保失敗,需要進(jìn)行Full GC
動(dòng)態(tài)年齡判定
新生代對(duì)象的年齡可能沒(méi)達(dá)到閾值(MaxTenuringThreshold參數(shù)指定)就晉升老年代器紧,如果Young GC之后耀销,新生代存活對(duì)象達(dá)到相同年齡所有對(duì)象大小的總和大于任一Survivor空間(S0 或 S1總空間)的一半,此時(shí)S0或者S1區(qū)即將容納不了存活的新生代對(duì)象铲汪,年齡大于或等于該年齡的對(duì)象就可以直接進(jìn)入老年代熊尉,無(wú)須等到MaxTenuringThreshold中要求的年齡
另外罐柳,如果Young GC后S0或S1區(qū)不足以容納:未達(dá)到晉升老年代條件的新生代存活對(duì)象,會(huì)導(dǎo)致這些存活對(duì)象直接進(jìn)入老年代狰住,需要盡量避免
CMS原理及調(diào)優(yōu)
1 名詞解釋
- 可達(dá)性分析算法:用于判斷對(duì)象是否存活张吉,基本思想是通過(guò)一系列稱為“GC Root”的對(duì)象作為起點(diǎn)(常見(jiàn)的GC Root有系統(tǒng)類(lèi)加載器、棧中的對(duì)象催植、處于激活狀態(tài)的線程等)肮蛹,基于對(duì)象引用關(guān)系,從GC Roots開(kāi)始向下搜索创南,所走過(guò)的路徑稱為引用鏈伦忠,當(dāng)一個(gè)對(duì)象到GC Root沒(méi)有任何引用鏈相連,證明對(duì)象不再存活
- Stop The World:GC過(guò)程中分析對(duì)象引用關(guān)系稿辙,為了保證分析結(jié)果的準(zhǔn)確性昆码,需要通過(guò)停頓所有Java執(zhí)行線程,保證引用關(guān)系不再動(dòng)態(tài)變化邻储,該停頓事件稱為Stop The World(STW)
- Safepoint:代碼執(zhí)行過(guò)程中的一些特殊位置赋咽,當(dāng)線程執(zhí)行到這些位置的時(shí)候,說(shuō)明虛擬機(jī)當(dāng)前的狀態(tài)是安全的芥备,如果有需要GC冬耿,線程可以在這個(gè)位置暫停。HotSpot采用主動(dòng)中斷的方式萌壳,讓執(zhí)行線程在運(yùn)行期輪詢是否需要暫停的標(biāo)志,若需要?jiǎng)t中斷掛起
2 CMS簡(jiǎn)介
CMS(Concurrent Mark and Sweep 并發(fā)-標(biāo)記-清除)日月,是一款基于并發(fā)袱瓮、使用標(biāo)記清除算法的垃圾回收算法,只針對(duì)老年代進(jìn)行垃圾回收爱咬。CMS收集器工作時(shí)尺借,盡可能讓GC線程和用戶線程并發(fā)執(zhí)行,以達(dá)到降低STW時(shí)間的目的
通過(guò)以下命令行參數(shù)精拟,啟用CMS垃圾收集器:
-XX:+UseConcMarkSweepGC
值得補(bǔ)充的是燎斩,下面介紹到的CMS GC是指老年代的GC,而Full GC指的是整個(gè)堆的GC事件蜂绎,包括新生代栅表、老年代、元空間等师枣,兩者有所區(qū)分
3 新生代垃圾回收
能與CMS搭配使用的新生代垃圾收集器有Serial收集器和ParNew收集器怪瓶。這2個(gè)收集器都采用標(biāo)記復(fù)制算法,都會(huì)觸發(fā)STW事件践美,停止所有的應(yīng)用線程洗贰。不同之處在于找岖,Serial是單線程執(zhí)行,ParNew是多線程執(zhí)行
4 老年代垃圾回收
CMS GC以獲取最小停頓時(shí)間為目的敛滋,盡可能減少STW時(shí)間许布,可以分為7個(gè)階段
階段 1: 初始標(biāo)記(Initial Mark)
此階段的目標(biāo)是標(biāo)記老年代中所有存活的對(duì)象, 包括 GC Root 的直接引用, 以及由新生代中存活對(duì)象所引用的對(duì)象,觸發(fā)第一次STW事件
這個(gè)過(guò)程是支持多線程的(JDK7之前單線程绎晃,JDK8之后并行蜜唾,可通過(guò)參數(shù)CMSParallelInitialMarkEnabled調(diào)整)
階段 2: 并發(fā)標(biāo)記(Concurrent Mark)
此階段GC線程和應(yīng)用線程并發(fā)執(zhí)行,遍歷階段1初始標(biāo)記出來(lái)的存活對(duì)象箕昭,然后繼續(xù)遞歸標(biāo)記這些對(duì)象可達(dá)的對(duì)象
階段 3: 并發(fā)預(yù)清理(Concurrent Preclean)
此階段GC線程和應(yīng)用線程也是并發(fā)執(zhí)行灵妨,因?yàn)殡A段2是與應(yīng)用線程并發(fā)執(zhí)行,可能有些引用關(guān)系已經(jīng)發(fā)生改變落竹。
通過(guò)卡片標(biāo)記(Card Marking)泌霍,提前把老年代空間邏輯劃分為相等大小的區(qū)域(Card),如果引用關(guān)系發(fā)生改變述召,JVM會(huì)將發(fā)生改變的區(qū)域標(biāo)記位“臟區(qū)”(Dirty Card)朱转,然后在本階段,這些臟區(qū)會(huì)被找出來(lái)积暖,刷新引用關(guān)系藤为,清除“臟區(qū)”標(biāo)記
階段 4: 并發(fā)可取消的預(yù)清理(Concurrent Abortable Preclean)
此階段也不停止應(yīng)用線程. 本階段嘗試在 STW 的 最終標(biāo)記階段(Final Remark)之前盡可能地多做一些工作,以減少應(yīng)用暫停時(shí)間
在該階段不斷循環(huán)處理:標(biāo)記老年代的可達(dá)對(duì)象夺刑、掃描處理Dirty Card區(qū)域中的對(duì)象缅疟,循環(huán)的終止條件有:
1 達(dá)到循環(huán)次數(shù)
2 達(dá)到循環(huán)執(zhí)行時(shí)間閾值
3 新生代內(nèi)存使用率達(dá)到閾值
階段 5: 最終標(biāo)記(Final Remark)
這是GC事件中第二次(也是最后一次)STW階段,目標(biāo)是完成老年代中所有存活對(duì)象的標(biāo)記遍愿。在此階段執(zhí)行:
1 遍歷新生代對(duì)象存淫,重新標(biāo)記
2 根據(jù)GC Roots,重新標(biāo)記
3 遍歷老年代的Dirty Card沼填,重新標(biāo)記
階段 6: 并發(fā)清除(Concurrent Sweep)
此階段與應(yīng)用程序并發(fā)執(zhí)行桅咆,不需要STW停頓,根據(jù)標(biāo)記結(jié)果清除垃圾對(duì)象
階段 7: 并發(fā)重置(Concurrent Reset)
此階段與應(yīng)用程序并發(fā)執(zhí)行坞笙,重置CMS算法相關(guān)的內(nèi)部數(shù)據(jù), 為下一次GC循環(huán)做準(zhǔn)備
5 CMS常見(jiàn)問(wèn)題
最終標(biāo)記階段停頓時(shí)間過(guò)長(zhǎng)問(wèn)題
CMS的GC停頓時(shí)間約80%都在最終標(biāo)記階段(Final Remark)岩饼,若該階段停頓時(shí)間過(guò)長(zhǎng),常見(jiàn)原因是新生代對(duì)老年代的無(wú)效引用薛夜,在上一階段的并發(fā)可取消預(yù)清理階段中籍茧,執(zhí)行閾值時(shí)間內(nèi)未完成循環(huán),來(lái)不及觸發(fā)Young GC却邓,清理這些無(wú)效引用
通過(guò)添加參數(shù):-XX:+CMSScavengeBeforeRemark硕糊。在執(zhí)行最終操作之前先觸發(fā)Young GC,從而減少新生代對(duì)老年代的無(wú)效引用,降低最終標(biāo)記階段的停頓简十,但如果在上個(gè)階段(并發(fā)可取消的預(yù)清理)已觸發(fā)Young GC檬某,也會(huì)重復(fù)觸發(fā)Young GC
并發(fā)模式失敗(concurrent mode failure) & 晉升失敗(promotion failed)問(wèn)題
并發(fā)模式失敗:當(dāng)CMS在執(zhí)行回收時(shí)螟蝙,新生代發(fā)生垃圾回收恢恼,同時(shí)老年代又沒(méi)有足夠的空間容納晉升的對(duì)象時(shí),CMS 垃圾回收就會(huì)退化成單線程的Full GC胰默。所有的應(yīng)用線程都會(huì)被暫停场斑,老年代中所有的無(wú)效對(duì)象都被回收
晉升失敗:當(dāng)新生代發(fā)生垃圾回收牵署,老年代有足夠的空間可以容納晉升的對(duì)象漏隐,但是由于空閑空間的碎片化,導(dǎo)致晉升失敗奴迅,此時(shí)會(huì)觸發(fā)單線程且?guī)嚎s動(dòng)作的Full GC
并發(fā)模式失敗和晉升失敗都會(huì)導(dǎo)致長(zhǎng)時(shí)間的停頓青责,常見(jiàn)解決思路如下:
- 降低觸發(fā)CMS GC的閾值,即參數(shù)-XX:CMSInitiatingOccupancyFraction的值取具,讓CMS GC盡早執(zhí)行脖隶,以保證有足夠的空間
- 增加CMS線程數(shù),即參數(shù)-XX:ConcGCThreads暇检,
- 增大老年代空間
- 讓對(duì)象盡量在新生代回收产阱,避免進(jìn)入老年代
內(nèi)存碎片問(wèn)題
通常CMS的GC過(guò)程基于標(biāo)記清除算法,不帶壓縮動(dòng)作块仆,導(dǎo)致越來(lái)越多的內(nèi)存碎片需要壓縮构蹬,常見(jiàn)以下場(chǎng)景會(huì)觸發(fā)內(nèi)存碎片壓縮:
- 新生代Young GC出現(xiàn)新生代晉升擔(dān)保失敗(promotion failed)
- 程序主動(dòng)執(zhí)行System.gc()
可通過(guò)參數(shù)CMSFullGCsBeforeCompaction的值,設(shè)置多少次Full GC觸發(fā)一次壓縮悔据,默認(rèn)值為0怎燥,代表每次進(jìn)入Full GC都會(huì)觸發(fā)壓縮,帶壓縮動(dòng)作的算法為上面提到的單線程Serial Old算法蜜暑,暫停時(shí)間(STW)時(shí)間非常長(zhǎng),需要盡可能減少壓縮時(shí)間
G1原理及調(diào)優(yōu)
G1(Garbage-First)是一款面向服務(wù)器的垃圾收集器策肝,支持新生代和老年代空間的垃圾收集肛捍,主要針對(duì)配備多核處理器及大容量?jī)?nèi)存的機(jī)器,G1最主要的設(shè)計(jì)目標(biāo)是: 實(shí)現(xiàn)可預(yù)期及可配置的STW停頓時(shí)間
2 G1堆空間劃分
Region
為實(shí)現(xiàn)大內(nèi)存空間的低停頓時(shí)間的回收之众,將劃分為多個(gè)大小相等的Region拙毫。每個(gè)小堆區(qū)都可能是 Eden區(qū),Survivor區(qū)或者Old區(qū)棺禾,但是在同一時(shí)刻只能屬于某個(gè)代
在邏輯上, 所有的Eden區(qū)和Survivor區(qū)合起來(lái)就是新生代缀蹄,所有的Old區(qū)合起來(lái)就是老年代,且新生代和老年代各自的內(nèi)存Region區(qū)域由G1自動(dòng)控制,不斷變動(dòng)
巨型對(duì)象
當(dāng)對(duì)象大小超過(guò)Region的一半缺前,則認(rèn)為是巨型對(duì)象(Humongous Object)蛀醉,直接被分配到老年代的巨型對(duì)象區(qū)(Humongous regions),這些巨型區(qū)域是一個(gè)連續(xù)的區(qū)域集衅码,每一個(gè)Region中最多有一個(gè)巨型對(duì)象拯刁,巨型對(duì)象可以占多個(gè)Region
G1把堆內(nèi)存劃分成一個(gè)個(gè)Region的意義在于:
每次GC不必都去處理整個(gè)堆空間,而是每次只處理一部分Region逝段,實(shí)現(xiàn)大容量?jī)?nèi)存的GC
通過(guò)計(jì)算每個(gè)Region的回收價(jià)值垛玻,包括回收所需時(shí)間、可回收空間奶躯,在有限時(shí)間內(nèi)盡可能回收更多的內(nèi)存帚桩,把垃圾回收造成的停頓時(shí)間控制在預(yù)期配置的時(shí)間范圍內(nèi),這也是G1名稱的由來(lái): garbage-first