JVM:垃圾收集器與內(nèi)存分配策略(下)

HotSpot算法實現(xiàn)

枚舉根節(jié)點:從GC Roots節(jié)點中找出引用鏈的操作策治。
GC Roots對象主要在全局性引用(常量/類靜態(tài)屬性)與執(zhí)行上下文(棧幀中的本地變量表)中厉膀,虛擬機不會逐個檢查這些地方,HotSpot使用OopMap數(shù)據(jù)結(jié)構(gòu)來記錄觅廓。當(dāng)類加載完成時鼻忠,OopMap中就記錄下對象內(nèi)為引用的位置,和棧杈绸、寄存器中引用的位置帖蔓。當(dāng)GC掃描時就可以直接得知引用信息矮瘟。

GC Roots.jpg

Stop The World:在可達性分析期間,需要這期間的一致性——不能一邊分析塑娇,對象的引用關(guān)系還一直變化澈侠,所以GC時必須停頓所有的Java執(zhí)行線程。

安全點:為了避免對每條指令都生成OopMap埋酬,而選擇的記錄信息的特定的位置哨啃。只有在安全點,程序才會停下來GC写妥。安全點的選定標(biāo)準(zhǔn):是否具有讓程序長時間執(zhí)行的特征拳球,例如,方法調(diào)用珍特、循環(huán)跳轉(zhuǎn)祝峻、異常跳轉(zhuǎn)。
讓所有線程都到最近的安全點再停頓的方法:

  • 搶先式中斷:先中斷所有線程次坡,再讓不在安全點的線程跑到安全點中斷呼猪。(幾乎不用)
  • 主動式中斷:設(shè)置標(biāo)志,各線程主動輪詢標(biāo)志砸琅,發(fā)現(xiàn)中斷標(biāo)志為真時就自己中斷掛起宋距。其中輪詢標(biāo)志的地方和安全點重合。

安全區(qū)域:針對不執(zhí)行的線程(sleep或blocked狀態(tài))設(shè)置症脂。當(dāng)線程進入安全區(qū)時谚赎,就標(biāo)識自己,GC時就不用管這些線程诱篷。當(dāng)線程要離開安全區(qū)時壶唤,要先檢查系統(tǒng)是否完成根節(jié)點枚舉(或GC),要完成了才能安全離開安全區(qū)棕所。

安全區(qū).jpg

垃圾收集器

HotSpot的垃圾收集器.jpg

新生代垃圾收集器

image.png
  • 對于單CPU環(huán)境闸盔,ParNew收集器不如Serial收集器效果好。其默認(rèn)開啟的GC線程數(shù)=CPU數(shù)量琳省,也可以使用-XX:ParallelGCThreads設(shè)置線程數(shù)迎吵。
  • 其他收集器專注縮短停頓用戶線程的時間,Parallel Scavenge專注于控制吞吐量针贬。吞吐量=CPU執(zhí)行用戶代碼的時間/(運行用戶代碼時間+垃圾收集時間)击费。高吞吐量即意味著可以高效利用CPU,盡快執(zhí)行完客戶代碼桦他。
    -XX:MaxGCPauseMillis:設(shè)定GC停頓的時間
    -XX:GCTimeRatio:設(shè)定垃圾收集時間占總時間的比率蔫巩,即吞吐量的倒數(shù)。
    -XX:+UseAdaptiveSizePolicy:打開此參數(shù)后,虛擬機動態(tài)調(diào)整新生代大小圆仔、Eden與Survivor區(qū)的比例垃瞧、晉升老年代對象大小等細(xì)節(jié)的參數(shù)。

老年代垃圾收集器

image.png

CMS收集器(Concurrent Mark Sweep)

  • 以獲取最短停頓時間為目標(biāo)的收集器
  • 適用于追求停頓時間最短的B/S系統(tǒng)服務(wù)端
  • 基于標(biāo)記-清楚算法


    CMS運行圖.jpg
  1. 初始標(biāo)記(CMS initial mark)
    STOP THE WORLD荧缘,標(biāo)記GC Roots能直接關(guān)聯(lián)的對象皆警,速度最快
  2. 并發(fā)標(biāo)記(CMS concurrent mark)
    進行GC Roots Tracing
  3. 重新標(biāo)記(CMS remark)
    STOP THE WORLD,修正在并發(fā)標(biāo)記期間有變動的對象標(biāo)記記錄
  4. 并發(fā)清除(CMS concurrent sweep)
    回收對象

缺點

  • 對CPU資源敏感
    在并發(fā)標(biāo)記和并發(fā)清理截粗,會占用CPU資源信姓,導(dǎo)致程序變慢,總吞吐量降低绸罗。CMS默認(rèn)啟動的回收線程數(shù)=(CPU數(shù)量+3)/4意推,當(dāng)CPU較少時,會對程序產(chǎn)生很大影響珊蟀。
  • 無法處理浮動垃圾(Floating Garbage)
    浮動垃圾指菊值,在并發(fā)清理階段產(chǎn)生的新的需要回收的對象。使用CMS收集器育灸,需要預(yù)留一部分內(nèi)存給用戶線程使用腻窒,如果在并發(fā)清理期間,預(yù)留內(nèi)存無法滿足程序需要磅崭,就會出現(xiàn)"Concurrent Mode Failure"儿子,然后臨時啟用Serial Old收集器來重新進行老年代的垃圾收集,導(dǎo)致停頓時間變長砸喻∪岜疲可以使用參數(shù)-XX:CMSInitiatingOccupancyFraction來設(shè)置CMS觸發(fā)的百分比。
  • 空間碎片
    CMS使用標(biāo)記-清理算法割岛,會產(chǎn)生大量空間碎片愉适。空間碎片過多時會影響大對象的分配癣漆。使用-XX:+UseCMSCompactAtFullCollection開關(guān)參數(shù)维咸,在要進行Full GC前,開啟內(nèi)存碎片的合并整理過程惠爽。但此操作不能并發(fā)癌蓖,會導(dǎo)致停頓時間增加。-XX:CMSFullGCsBeforeCompaction則設(shè)置疆股,在執(zhí)行n次不壓縮的Full GC后,執(zhí)行一次碎片整理的Full GC倒槐。

G1收集器(Garbage-first)

適用于服務(wù)器端旬痹。
優(yōu)點:

  • 并行與并發(fā)
    與CMS相似。
  • 分代收集
    可以不與其他收集器配合,獨立管理整個GC堆两残,并在不同的代里使用不同的收集算法永毅。
  • 空間整合
    G1運作期間不會產(chǎn)生內(nèi)存空間碎片,有利于程序長時間運行人弓,不會因為沒有足夠的空間分配給大對象而提前觸發(fā)GC沼死。
  • 可預(yù)測停頓
    可以建立可預(yù)測的停頓時間模型,讓使用者明確指定在一個長度為M毫秒的時間片段中崔赌,消耗在垃圾收集上的時間不超過N毫秒意蛀。
    G1將Java堆劃分為多個大小相等的獨立區(qū)域(Region),雖然也分新生代健芭、老年代县钥,但他們都是一部分Region的集合,不存在物理隔離慈迈。G1根據(jù)各個Region中垃圾堆積的價值大腥糁(回收后可以獲得的空間大小和回收所需時間的經(jīng)驗值),在后臺維護一個優(yōu)先列表痒留,每次根據(jù)用戶允許的收集時間谴麦,優(yōu)先回收價值最大的Region。其難點在于伸头,Region不是孤立的匾效,一個對象會被其他Region的對象引用。在做可達性分析尋找可回收對象時熊锭,需要掃描整個Java堆才能保證準(zhǔn)確性弧轧。G1使用Remembered Set來避免全堆掃描。每個Region對應(yīng)一個Remembered Set碗殷,當(dāng)程序?qū)σ妙愋偷臄?shù)據(jù)進行寫操作時精绎,虛擬機產(chǎn)生一個Write Barrier暫時中斷操作,檢查引用的對象是否處于不同的Region锌妻,如果是的話代乃,就通過CardTable把相關(guān)應(yīng)用信息記錄到被引用對象所屬的Region的Remembered Set中。進行內(nèi)存回收的時候仿粹,在GC根節(jié)點枚舉范圍加上Remembered Set搁吓。


    G1收集器運行圖.jpg
  1. 初始標(biāo)記
  2. 并發(fā)標(biāo)記
  3. 最終標(biāo)記
    STOP THE WORLD,可并發(fā)執(zhí)行最終標(biāo)記吭历。修正并發(fā)標(biāo)記期間有變動的對象記錄堕仔,虛擬機將這些變化記錄在線程Remembered Set Logs里面,再合并到Remembered Set中晌区。
  4. 篩選回收
    STOP THE WORLD摩骨,可并發(fā)執(zhí)行通贞。對各個Region的回收價值和成本進行排序,根據(jù)用戶的需求來指定回收計劃恼五。

GC日志

// 參數(shù):-verbose:gc -Xms20M -Xmx20M -Xmn10M -XX:+PrintGCDetails -XX:SurvivorRatio=8
[GC (Allocation Failure) [PSYoungGen: 7128K->616K(9216K)] 7128K->6768K(19456K), 0.0057651 secs] [Times: user=0.00 sys=0.00, real=0.01 secs] 
[Full GC (Ergonomics) [PSYoungGen: 616K->0K(9216K)] [ParOldGen: 6152K->6658K(10240K)] 6768K->6658K(19456K), [Metaspace: 2542K->2542K(1056768K)], 0.0066751 secs] [Times: user=0.00 sys=0.00, real=0.01 secs] 
  • GC/FULL GC:說明垃圾回收的停頓類型昌罩,full gc是發(fā)生了stop the world的。
  • PSYoungGen/ParOldGen:發(fā)生GC的區(qū)域灾馒。
    PSYoungGen:Parallel Scavenge收集器新生代
    DefNew:Default New Generation茎用,使用Serial收集器中的新生代
    ParNew:ParNew收集器的新生代
    ParOldGen:Parallel Old 的老年代
  • 7128K->616K(9216K):GC前該內(nèi)存區(qū)域已使用容量->GC后已使用容量(總?cè)萘浚?/li>
  • 7128K->6768K(19456K)(方括號外):GC前java堆已使用容量->GC后已使用容量(java堆總?cè)萘浚?/li>
  • 0.0057651 secs:GC所占用時間(秒)。
  • [Times: user=0.00 sys=0.00, real=0.01 secs] :【用戶態(tài)消耗CPU時間睬罗,內(nèi)核態(tài)消耗CPU時間轨功,墻鐘時間(Wall Clock Time)】。墻鐘時間 = 非運算等待耗時(磁盤IO/線程阻塞等待時間) + CPU時間傅物。

內(nèi)存分配與回收策略

  • 優(yōu)先在Eden上分配
    優(yōu)先在Eden上分配夯辖,Eden空間不夠時,發(fā)起Minor GC董饰,將存活對象移到Survivor中去蒿褂。
  • 大對象直接進入老年代
    大對象,即需要大量連續(xù)內(nèi)存空間的Java對象(如很長的字符串卒暂、數(shù)組)啄栓。通過-XX:PretenureSizeThreshold參數(shù),大于這個值的對象都會直接在老年代中進行分配也祠。
  • 長期存活對象進入老年代
    計算對象的對象年齡計數(shù)器昙楚,新生代的對象每熬過一次Minor GC,年齡就加1诈嘿。年齡超過-XX:MaxTenuringThreshold參數(shù)的對象堪旧,就會被晉升到老年代。
  • 動態(tài)對象年齡判斷
    在Survivor空間中奖亚,相同年齡所有對象的大小總和大于Survivor空間的一般時淳梦,大于這個年齡的對象就會被晉升到老年代。
  • 空間分配擔(dān)保
    Minor GC前昔字,虛擬機先檢查老年代的最大可用的連續(xù)空間爆袍,是否大于新生代所有對象總空間。如果不成立作郭,就查看HandlePromotionFailure設(shè)置的值是否允許擔(dān)保失敗陨囊。如果允許,檢查老年代最大可用的連續(xù)空間夹攒,是否大于歷次晉升到老年代的對象的平均大小蜘醋。如果大于,就嘗試進行Minor GC咏尝,否則就進行Full GC压语。
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末闲先,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子无蜂,更是在濱河造成了極大的恐慌,老刑警劉巖蒙谓,帶你破解...
    沈念sama閱讀 222,464評論 6 517
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件斥季,死亡現(xiàn)場離奇詭異,居然都是意外死亡累驮,警方通過查閱死者的電腦和手機酣倾,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 95,033評論 3 399
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來谤专,“玉大人躁锡,你說我怎么就攤上這事≈檬蹋” “怎么了映之?”我有些...
    開封第一講書人閱讀 169,078評論 0 362
  • 文/不壞的土叔 我叫張陵,是天一觀的道長蜡坊。 經(jīng)常有香客問我杠输,道長,這世上最難降的妖魔是什么秕衙? 我笑而不...
    開封第一講書人閱讀 59,979評論 1 299
  • 正文 為了忘掉前任蠢甲,我火速辦了婚禮,結(jié)果婚禮上据忘,老公的妹妹穿的比我還像新娘鹦牛。我一直安慰自己,他們只是感情好勇吊,可當(dāng)我...
    茶點故事閱讀 69,001評論 6 398
  • 文/花漫 我一把揭開白布曼追。 她就那樣靜靜地躺著,像睡著了一般萧福。 火紅的嫁衣襯著肌膚如雪拉鹃。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 52,584評論 1 312
  • 那天鲫忍,我揣著相機與錄音膏燕,去河邊找鬼。 笑死悟民,一個胖子當(dāng)著我的面吹牛坝辫,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播射亏,決...
    沈念sama閱讀 41,085評論 3 422
  • 文/蒼蘭香墨 我猛地睜開眼近忙,長吁一口氣:“原來是場噩夢啊……” “哼竭业!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起及舍,我...
    開封第一講書人閱讀 40,023評論 0 277
  • 序言:老撾萬榮一對情侶失蹤未辆,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后锯玛,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體咐柜,經(jīng)...
    沈念sama閱讀 46,555評論 1 319
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 38,626評論 3 342
  • 正文 我和宋清朗相戀三年攘残,在試婚紗的時候發(fā)現(xiàn)自己被綠了拙友。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 40,769評論 1 353
  • 序言:一個原本活蹦亂跳的男人離奇死亡歼郭,死狀恐怖遗契,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情病曾,我是刑警寧澤牍蜂,帶...
    沈念sama閱讀 36,439評論 5 351
  • 正文 年R本政府宣布,位于F島的核電站泰涂,受9級特大地震影響捷兰,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜负敏,卻給世界環(huán)境...
    茶點故事閱讀 42,115評論 3 335
  • 文/蒙蒙 一贡茅、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧其做,春花似錦顶考、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,601評論 0 25
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至蹈胡,卻和暖如春渊季,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背罚渐。 一陣腳步聲響...
    開封第一講書人閱讀 33,702評論 1 274
  • 我被黑心中介騙來泰國打工却汉, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人荷并。 一個月前我還...
    沈念sama閱讀 49,191評論 3 378
  • 正文 我出身青樓合砂,卻偏偏與公主長得像,于是被迫代替她去往敵國和親源织。 傳聞我的和親對象是個殘疾皇子翩伪,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 45,781評論 2 361

推薦閱讀更多精彩內(nèi)容