深入理解java虛擬機(jī)(第二版)——第三章:垃圾收集器與內(nèi)存分配策略

一、對(duì)象存活統(tǒng)計(jì)算法

1.引用計(jì)數(shù)器法

每當(dāng)對(duì)象被引用一次時(shí)劣砍,計(jì)數(shù)器的值就加一惧蛹;當(dāng)引用失效時(shí),計(jì)數(shù)器的值就減一刑枝。在任何時(shí)刻香嗓,計(jì)數(shù)器為0的值時(shí)不會(huì)被使用的。
優(yōu)點(diǎn):實(shí)現(xiàn)簡(jiǎn)單装畅,判定效率高靠娱。
缺點(diǎn):無(wú)法解決對(duì)象之間相互調(diào)用的問(wèn)題。

publicclassReferenceCountingGC{
  publicObject instance =null;publicstaticvoidtestGC(){        
    ReferenceCountingGC objA =newReferenceCountingGC();        
    ReferenceCountingGC objB =newReferenceCountingGC();        
    objA.instance = objB;        
    objB.instance = objA;        
    objA =null;        
    objB =null;        
    System.gc();    
  }
}

上面代碼在gc之后objA和objB會(huì)回收掠兄,所以虛擬機(jī)并沒(méi)有使用引用計(jì)數(shù)法像云。

2.可達(dá)分析計(jì)算

該方法以一系列“GC Roots”的對(duì)象作為起始點(diǎn),從這些節(jié)點(diǎn)開(kāi)始向下搜索蚂夕,搜索走過(guò)的路徑稱為引用鏈迅诬,當(dāng)一個(gè)對(duì)象到GC Roots沒(méi)有任何引用鏈條時(shí),則證明對(duì)象是不可用的婿牍。在java中侈贷,可以作為GC Roots的對(duì)象包括:
虛擬機(jī)棧中引用的對(duì)象。
方法區(qū)中靜態(tài)屬性引用的對(duì)象等脂。
方法區(qū)中常量引用的對(duì)象
本地方法棧中引用的對(duì)象

二俏蛮、對(duì)象的死亡過(guò)程

處在可達(dá)性分型中不可達(dá)的對(duì)象,暫時(shí)處于緩刑階段上遥。具體的死亡過(guò)程如下:


image

其中搏屑,判斷finalize()方法是否 需要執(zhí)行的標(biāo)準(zhǔn)有兩個(gè):
finalize()方法有沒(méi)有被重寫(xiě),沒(méi)被重寫(xiě)不調(diào)用
finalize()方法已經(jīng)執(zhí)行過(guò)粉楚,不調(diào)用辣恋。
換句話說(shuō),一個(gè)對(duì)象只有重寫(xiě)了finalize()方法并且第一個(gè)執(zhí)行,虛擬機(jī)才會(huì)執(zhí)行該對(duì)象的finalize()方法抑党。

三包警、垃圾收集算法

1.標(biāo)記-清除算法

標(biāo)記清除算法是最基礎(chǔ)的算法,此算法分為兩個(gè)階段標(biāo)記和清除
標(biāo)記:標(biāo)記需要回收的對(duì)象
清除:統(tǒng)一回收被標(biāo)記的對(duì)象底靠。
缺點(diǎn):效率低害晦,標(biāo)記和清除兩個(gè)過(guò)程的效率都不高。清除后會(huì)產(chǎn)生大量的碎片空間暑中,在分配大對(duì)象時(shí)碎片空間無(wú)法利用會(huì)觸發(fā)另一次垃圾回收壹瘟。

2.復(fù)制算法

復(fù)制算法講內(nèi)存分為大小相同的兩塊,當(dāng)一塊使用完了之后將其中存活的對(duì)象復(fù)制到另一塊上面鳄逾。然后將之前的內(nèi)存空間整個(gè)清理掉稻轨。復(fù)制算法的具體過(guò)程分為
標(biāo)記:區(qū)分存活和需要收集的對(duì)象
復(fù)制:將存活的對(duì)象諸葛復(fù)制到新的空間
清理:將就得空間一次性清理掉
優(yōu)點(diǎn):復(fù)制后新空間和舊空間沒(méi)有內(nèi)存碎片。新對(duì)象的分配簡(jiǎn)單高效雕凹,只要一動(dòng)指針即可殴俱。
缺點(diǎn): 代價(jià)高昂,可用內(nèi)存縮小為了原來(lái)的一半枚抵。
復(fù)制算法的變種:
人們發(fā)現(xiàn)在新生代區(qū)使用復(fù)制算法時(shí)线欲,死亡對(duì)象的比例約為98%,即每次需要復(fù)制的存活對(duì)象大約只有2%汽摹,這樣就不需要將原內(nèi)存劃分為兩塊1:1的內(nèi)存李丰,而是根據(jù)新生代的特點(diǎn)分成8:1:1的三塊內(nèi)存,eden區(qū)占8逼泣,兩塊survivor分別占1趴泌。每次使用eden和一塊survivor,當(dāng)回收后將eden'和survivor存活的對(duì)象復(fù)制到另一塊survivor上拉庶,這樣講復(fù)制算法原來(lái)的浪費(fèi)一半的內(nèi)存空間壓縮到10%嗜憔。但是這樣并不總是保險(xiǎn)的,即有時(shí)候存活的對(duì)象會(huì)超過(guò)10%砍的,這時(shí)另一塊survivor空間就會(huì)放不下痹筛。這時(shí)jvm的做法是向老年代借一塊空間來(lái)存放存活對(duì)象莺治。這叫做分配擔(dān)保廓鞠,即當(dāng)survivor空間不夠時(shí)由老年代擔(dān)保可以將不夠的空間從老年代劃出使用谣旁。

3.標(biāo)記-整理算法

前面的復(fù)制算法適用于存活對(duì)象較少的區(qū)域床佳,如果存活對(duì)象較多時(shí)存活空間劃分較小會(huì)頻繁觸發(fā)分配擔(dān)保,這樣可能會(huì)影響到擔(dān)遍螅空間的正常使用砌们,如果擔(dān)保空間不夠用觸發(fā)full GC會(huì)使垃圾收集的效率大大降低。
標(biāo)記-整理算法時(shí)適用于老年代的算法浪感。需要兩個(gè)步驟
標(biāo)記:標(biāo)記存活對(duì)象
整理:將存活對(duì)象移動(dòng)到空間的一端昔头,將端邊界以外的空間都清理掉。移動(dòng)的時(shí)候不管要清理的對(duì)象影兽。直接讓存活對(duì)象覆蓋揭斧。之后整體清理。

四峻堰、Hotspot的算法實(shí)現(xiàn)

1.枚舉根節(jié)點(diǎn)

在根節(jié)點(diǎn)枚舉中讹开,GCRoots的主要節(jié)點(diǎn)在全局性的引用和執(zhí)行上下文中,如果逐個(gè)檢查會(huì)很消耗時(shí)間捐名。
另外可達(dá)性分析要求執(zhí)行系統(tǒng)必須凍結(jié)在某個(gè)時(shí)間點(diǎn)上旦万,不可以出現(xiàn)分析過(guò)程中引用關(guān)系還在出現(xiàn)不斷變化的過(guò)程中。
HotSpot的準(zhǔn)確式GC
HotSpot采用了準(zhǔn)確式GC以提升GC roots的枚舉速度镶蹋。所謂準(zhǔn)確式GC成艘,就是讓JVM知道內(nèi)存中某位置數(shù)據(jù)的類型什么。比如當(dāng)前內(nèi)存位置中的數(shù)據(jù)究竟是一個(gè)整型變量還是一個(gè)引用類型贺归。這樣JVM可以很快確定所有引用類型的位置狰腌,從而更有針對(duì)性的進(jìn)行GC roots枚舉。HotSpot是利用OopMap來(lái)實(shí)現(xiàn)準(zhǔn)確式GC的牧氮。當(dāng)類加載完成后琼腔,HotSpot 就將對(duì)象內(nèi)存布局之中什么偏移量上數(shù)值是一個(gè)什么樣的類型的數(shù)據(jù)這些信息存放到 OopMap 中;在 HotSpot 的 JIT 編譯過(guò)程中踱葛,同樣會(huì)插入相關(guān)指令來(lái)標(biāo)明哪些位置存放的是對(duì)象引用等丹莲,這樣在 GC 發(fā)生時(shí),HotSpot 就可以直接掃描 OopMap 來(lái)獲取對(duì)象引用的存儲(chǔ)位置尸诽,從而進(jìn)行 GC Roots 枚舉甥材。

2.serial收集器

是最古老的也是最基礎(chǔ)的收集器,單線程是因?yàn)楫?dāng)他在進(jìn)行工作時(shí)必須停止其他活動(dòng)的線程
優(yōu)點(diǎn):簡(jiǎn)單高效性含,沒(méi)有線程切換帶來(lái)的開(kāi)銷洲赵。在個(gè)人桌面管理中,stop the world的時(shí)間一般能控制在幾十毫秒商蕴,在這時(shí)使用serial收集器是很好的選擇叠萍。

3.ParNew收集器

parNew是serial的多線程版本,注意在parnew工作時(shí)仍然會(huì)停止其他工作線程绪商。不同的是相比于serial苛谷,parnew采用多線程的方式回收垃圾。在多核cpu時(shí)收集速度會(huì)明顯的高于serial格郁。但是在單核或者核心較少的機(jī)器中腹殿,serial會(huì)高于parnew的收集速度独悴。

4.parallel scavenge收集器

是一個(gè)新生代收集器,使用復(fù)制算法锣尉,并行收集刻炒。
特點(diǎn):關(guān)注吞吐量。吞吐量=客戶代碼運(yùn)行時(shí)間/(客戶代碼運(yùn)行時(shí)間+垃圾收集時(shí)間)
兩個(gè)重要的參數(shù):
MaxGCPauseMillis:最大垃圾收集停頓時(shí)間自沧。太大垃圾收集停頓時(shí)間明顯落蝙,影響用戶體驗(yàn)。太小導(dǎo)致垃圾收集不完整暂幼,容易觸發(fā)頻繁的GC筏勒,降低吞吐量。
GCTimeRatio:垃圾收集時(shí)間占比旺嬉。計(jì)算方式為:用戶代碼運(yùn)行時(shí)間/垃圾收集時(shí)間管行。如19 = 19:1,實(shí)際垃圾收集時(shí)間為1:(19+1) = 5%

5.serial old收集器

serial old類似于serial收集器邪媳,serial一般使用于新生代捐顷,serial old適用于老年代。采用的收集算法是標(biāo)記-整理雨效。主要的使用場(chǎng)景:
主要使用于client模式下的虛擬機(jī)
在server模式下迅涮,當(dāng)CMS并發(fā)收集失敗時(shí),作為CMS的后備方案徽龟。

6.parallel old收集器

parallel old是parallel scavenge的老年代版本叮姑。采用標(biāo)記-整理算法。
主要使用場(chǎng)景為配合新生代paralle scavenge使用据悔,使得“吞吐量?jī)?yōu)先的概念”成為名副其實(shí)传透。在paralle old出現(xiàn)之前,parallel scavenge只能和serial old配合极颓,由于serial old是單線程的版本朱盐,在多核cpu中能力有限,使得新生代的parallen scavenge的“吞吐量?jī)?yōu)先”效果有限菠隆。

7.CMS(cocurrent mark sweep)收集器

是并發(fā)清除收集器兵琳,強(qiáng)調(diào)以最短的收集停頓時(shí)間為目的。相比于前幾個(gè)收集器骇径,CMS比較復(fù)雜躯肌。整個(gè)過(guò)程分為4個(gè)步驟:
初始標(biāo)記:僅僅標(biāo)記GC Roots能直接關(guān)聯(lián)到的對(duì)象。
并發(fā)標(biāo)記:進(jìn)行GC Roots Tracing過(guò)程既峡。
重新標(biāo)記:修正并發(fā)期間因用戶程序繼續(xù)運(yùn)作而導(dǎo)致標(biāo)記產(chǎn)生變化的一部分對(duì)象的標(biāo)記記錄
并發(fā)清除:最后多線程清除已標(biāo)記兩次的對(duì)象羡榴。
其中初始標(biāo)記和和重新標(biāo)記兩個(gè)過(guò)程需要stop the world碧查。最耗時(shí)的是并發(fā)標(biāo)記和并發(fā)整理运敢,由于這兩個(gè)過(guò)程是與用戶線程并發(fā)進(jìn)行的所以總體來(lái)說(shuō)CMS可以說(shuō)成是并行的垃圾收集器校仑。除了以上優(yōu)點(diǎn),CMS的缺點(diǎn)如下:
缺點(diǎn):
CMS對(duì)CPU資源非常敏感传惠。CMS默認(rèn)的回收線程數(shù)為(cpu核心+3)/4迄沫,看以看到當(dāng)cpu核心數(shù)增多時(shí)CMS線程的變化趨勢(shì)為 1->四份之一的總核心數(shù)。即當(dāng)cpu越多時(shí)CMS占用的資源越少卦方。當(dāng)cpu核心越少羊瘩,CMS占用的資源越多,嚴(yán)重影響用戶代碼的執(zhí)行盼砍。分析這種情況尘吗,當(dāng)運(yùn)行并發(fā)標(biāo)記和并發(fā)清除時(shí),CMS線程獨(dú)占CPU浇坐,使得用戶線程停滯或者分配到其他CPU睬捶,此時(shí)用戶代碼執(zhí)行速度大大降低。在這種情況下提出了i-CMS近刘,改變點(diǎn)就是在CMS執(zhí)行并發(fā)標(biāo)和并發(fā)清除時(shí)和用戶線程交替運(yùn)行擒贸,此時(shí)的CMS線程是并行收集嗎?(未確定)觉渴,這樣整個(gè)垃圾收集的過(guò)程會(huì)拉長(zhǎng)介劫,但是用戶代碼執(zhí)行效率提高了。實(shí)踐證明不好用案淋。
并發(fā)清除時(shí)用戶線程會(huì)產(chǎn)生新的垃圾座韵,這些垃圾稱為浮動(dòng)垃圾。由于并發(fā)性踢京,所以需要在清除時(shí)需要額外的空間給用戶線程使用回右。所以CMS一般需要預(yù)留一塊內(nèi)存,而垃圾收集也并不是在老年代填滿了才進(jìn)行漱挚。使用CMSInitiatingOccupancyFraction控制觸發(fā)垃圾回收的內(nèi)存占比翔烁。當(dāng)調(diào)的太高時(shí),可能預(yù)留空間會(huì)無(wú)法滿足浮動(dòng)垃圾的使用從而產(chǎn)生Cocurrent Mode Failure旨涝。此時(shí)采用serial old收集器蹬屹。調(diào)的太小則硬件浪費(fèi)嚴(yán)重。
CMS的收集算法是標(biāo)記-清除白华,所以會(huì)空間碎片慨默。如果大對(duì)象無(wú)法分配內(nèi)存則會(huì)觸發(fā)Full GC 。為了解決這個(gè)問(wèn)題弧腥,使用-XX:+UseCMSCompactAtFullCollection參數(shù)控制在CMS收集完后進(jìn)行空間整理厦取。由于內(nèi)存整理無(wú)法并發(fā),所以在整理時(shí)會(huì)停掉用戶線程管搪,增加停頓時(shí)間虾攻。因此在此基礎(chǔ)上增加了-XX:CMSFullGCsBeforeCompaction來(lái)控制執(zhí)行n次不壓縮的CMS后來(lái)一次整理空間的CMS铡买。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
禁止轉(zhuǎn)載,如需轉(zhuǎn)載請(qǐng)通過(guò)簡(jiǎn)信或評(píng)論聯(lián)系作者霎箍。
  • 序言:七十年代末奇钞,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子漂坏,更是在濱河造成了極大的恐慌景埃,老刑警劉巖,帶你破解...
    沈念sama閱讀 212,816評(píng)論 6 492
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件顶别,死亡現(xiàn)場(chǎng)離奇詭異谷徙,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī)驯绎,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,729評(píng)論 3 385
  • 文/潘曉璐 我一進(jìn)店門蒂胞,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人条篷,你說(shuō)我怎么就攤上這事骗随。” “怎么了赴叹?”我有些...
    開(kāi)封第一講書(shū)人閱讀 158,300評(píng)論 0 348
  • 文/不壞的土叔 我叫張陵鸿染,是天一觀的道長(zhǎng)。 經(jīng)常有香客問(wèn)我乞巧,道長(zhǎng)涨椒,這世上最難降的妖魔是什么? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 56,780評(píng)論 1 285
  • 正文 為了忘掉前任绽媒,我火速辦了婚禮蚕冬,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘是辕。我一直安慰自己囤热,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,890評(píng)論 6 385
  • 文/花漫 我一把揭開(kāi)白布获三。 她就那樣靜靜地躺著旁蔼,像睡著了一般。 火紅的嫁衣襯著肌膚如雪疙教。 梳的紋絲不亂的頭發(fā)上棺聊,一...
    開(kāi)封第一講書(shū)人閱讀 50,084評(píng)論 1 291
  • 那天,我揣著相機(jī)與錄音贞谓,去河邊找鬼限佩。 笑死,一個(gè)胖子當(dāng)著我的面吹牛裸弦,可吹牛的內(nèi)容都是我干的祟同。 我是一名探鬼主播作喘,決...
    沈念sama閱讀 39,151評(píng)論 3 410
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼耐亏!你這毒婦竟也來(lái)了徊都?” 一聲冷哼從身側(cè)響起沪斟,我...
    開(kāi)封第一講書(shū)人閱讀 37,912評(píng)論 0 268
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤广辰,失蹤者是張志新(化名)和其女友劉穎,沒(méi)想到半個(gè)月后主之,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體择吊,經(jīng)...
    沈念sama閱讀 44,355評(píng)論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,666評(píng)論 2 327
  • 正文 我和宋清朗相戀三年槽奕,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了几睛。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 38,809評(píng)論 1 341
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡粤攒,死狀恐怖所森,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情夯接,我是刑警寧澤焕济,帶...
    沈念sama閱讀 34,504評(píng)論 4 334
  • 正文 年R本政府宣布,位于F島的核電站盔几,受9級(jí)特大地震影響晴弃,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜逊拍,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 40,150評(píng)論 3 317
  • 文/蒙蒙 一上鞠、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧芯丧,春花似錦芍阎、人聲如沸。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 30,882評(píng)論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至肿轨,卻和暖如春寿冕,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背椒袍。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 32,121評(píng)論 1 267
  • 我被黑心中介騙來(lái)泰國(guó)打工驼唱, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人驹暑。 一個(gè)月前我還...
    沈念sama閱讀 46,628評(píng)論 2 362
  • 正文 我出身青樓玫恳,卻偏偏與公主長(zhǎng)得像辨赐,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子京办,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,724評(píng)論 2 351