本篇內(nèi)容主要講解“垃圾回收CMS的過程是怎樣的”,感興趣的朋友不妨來看看。本文介紹的方法操作簡單快捷,實用性強。下面就讓小編來帶大家學習“垃圾回收CMS的過程是怎樣的”吧!
10年積累的成都做網(wǎng)站、成都網(wǎng)站建設(shè)經(jīng)驗,可以快速應(yīng)對客戶對網(wǎng)站的新想法和需求。提供各種問題對應(yīng)的解決方案。讓選擇我們的客戶得到更好、更有力的網(wǎng)絡(luò)服務(wù)。我雖然不認識你,你也不認識我。但先制作網(wǎng)站后付款的網(wǎng)站建設(shè)流程,更有信陽免費網(wǎng)站建設(shè)讓你可以放心的選擇與我們合作。
全稱 Concurrent Mark Sweep,是一款并發(fā)的、使用標記-清除算法的垃圾回收器。
1、并行,STW時間短暫。
2、沒有壓縮和整理,產(chǎn)生內(nèi)存碎片。
對象在標記過程中,根據(jù)標記情況,分成三類:
1、白色對象,表示自身未被標記;
2、灰色對象,表示自身被標記,但內(nèi)部引用未被處理;
3、黑色對象,表示自身被標記,內(nèi)部引用都被處理;
觸發(fā)時間:如果添加了一下參數(shù)
當老年代的使用率達到80%時,就會觸發(fā)一次cms gc。
假設(shè)CMS GC之前的堆結(jié)構(gòu)如下圖:
這是一個STW過程,主要分兩步
1、標記GC Roots可達的老年代對象;
2、遍歷GC Roots下的新生代對象能夠可達的老年代對象;
3、此過程不對以上可達的老年代對象進行進一步的可達掃描。
結(jié)果:
該階段GC線程和應(yīng)用線程并發(fā)執(zhí)行,遍歷InitialMarking階段標記出來的存活對象,然后繼續(xù)遞歸標記這些對象可達的對象。
這個過程應(yīng)用線程在運行,可能Young GC也會發(fā)生,會發(fā)生以下的情況:
1、新生代對象晉升到老年代
2、在老年代分配對象
3、新老年代對象的引用發(fā)生變化。
結(jié)果:
CMS使用上一節(jié)講過的Card Table來解決這個問題
并發(fā)標記過程中引用發(fā)生變化的對象所在的Card,在Card Table來記錄為“臟卡”,這樣在后面重新標記的時候會把這些對象也當做GC Root來遍歷
但是Young GC如果發(fā)生,比方說:
1、并發(fā)標記還未掃描到臟卡1.
2、Young GC掃描完臟卡,并改變dirty到clean.
3、并發(fā)標記掃描,發(fā)現(xiàn)卡1已不是臟卡,則不會處理,這就造成了漏標。
CMS中,有另一種數(shù)據(jù)結(jié)構(gòu)(Mod Union Table)
Mod Union Table是一個位向量,每個單元的大小只有1位,每個單元對應(yīng)一個Card(Card的大小是512字節(jié),Card Table每一個單元的大小是1個字節(jié))
在新生代GC處理dirty card之前,先把該card在Mod Union Table里面的對應(yīng)項置位。
這樣,CMS在執(zhí)行重新標記階段的時候,就會掃描Mod Union Table和card table里面被標記的項。
通過參數(shù)CMSPrecleaningEnabled選擇關(guān)閉該階段,默認啟用,主要做兩件事情:
1、處理新生代已經(jīng)發(fā)現(xiàn)的引用,比如在并發(fā)階段,在Eden區(qū)中分配了一個A對象,A對象引用了一個老年代對象B(這個B之前沒有被標記),在這個階段就會標記對象B為活躍對象。
2、在并發(fā)標記階段,如果老年代中有對象內(nèi)部引用發(fā)生變化,會把所在的Card標記為Dirty(包括ModUnionTalble),通過掃描這些Table,重新標記那些在并發(fā)標記階段引用被更新的對象。
該階段發(fā)生的前提是,新生代Eden區(qū)的內(nèi)存使用量大于參數(shù)CMSScheduleRemarkEdenSizeThreshold 默認是2M,如果新生代的對象太少,就沒有必要執(zhí)行該階段,直接執(zhí)行重新標記階段。
因為CMS GC的終極目標是降低垃圾回收時的暫停時間,所以在該階段要盡最大的努力去處理那些在并發(fā)階段被應(yīng)用線程更新的老年代對象,這樣在暫停的重新標記階段就可以少處理一些,暫停時間也會相應(yīng)的降低。
在該階段,主要循環(huán)的做兩件事:
1、處理 From 和 To 區(qū)的對象,標記可達的老年代對象
2、和上一個階段一樣,掃描處理Dirty Card和ModUnionTalble中的對象。
當然了,這個邏輯不會一直循環(huán)下去,打斷這個循環(huán)的條件有三個:
1、可以設(shè)置最多循環(huán)的次數(shù) CMSMaxAbortablePrecleanLoops,默認是0,意思沒有循環(huán)次數(shù)的限制。
2、如果執(zhí)行這個邏輯的時間達到了閾值CMSMaxAbortablePrecleanTime,默認是5s,會退出循環(huán)。
3、如果新生代Eden區(qū)的內(nèi)存使用率達到了閾值CMSScheduleRemarkEdenPenetration,默認50%,會退出循環(huán)。
在之前的并行階段,可能產(chǎn)生新的引用關(guān)系如下:
1、老年代的新對象被GC Roots引用
2、老年代的未標記對象被新生代對象引用
3、老年代已標記的對象增加新引用指向老年代其它對象
4、新生代對象指向老年代引用被刪除
上述對象中可能有一些已經(jīng)在Precleaning階段和AbortablePreclean階段被處理過,但總存在沒來得及處理的,所以需要做以下事情:
1、遍歷新生代對象,重新標記
2、根據(jù)GC Roots,重新標記
3、遍歷老年代的Dirty Card和Mod Union Table,重新標記
在第1步驟中,需要遍歷新生代的全部對象,如果新生代的使用率很高,需要遍歷處理的對象也很多,這對于這個階段的總耗時來說,是個災(zāi)難(因為可能大量的對象是暫時存活的,而且這些對象也可能引用大量的老年代對象,造成很多應(yīng)該回收的老年代對象而沒有被回收,遍歷遞歸的次數(shù)也增加不少),如果在這之前發(fā)生一次YGC,這樣就可以避免掃描無效的對象。
CMS算法中提供了一個參數(shù):CMSScavengeBeforeRemark,默認并沒有開啟,如果開啟該參數(shù),在執(zhí)行該階段之前,會強制觸發(fā)一次YGC,可以減少新生代對象的遍歷時間,回收的也更徹底一點。
清理在標記階段收集標識為不可達的對象
清除數(shù)據(jù)結(jié)構(gòu),準備下一次并發(fā)收集。
到此,相信大家對“垃圾回收CMS的過程是怎樣的”有了更深的了解,不妨來實際操作一番吧!這里是創(chuàng)新互聯(lián)網(wǎng)站,更多相關(guān)內(nèi)容可以進入相關(guān)頻道進行查詢,關(guān)注我們,繼續(xù)學習!