轉自:http://javis163.iteye.com/blog/1679059數據結構
當使用CMS收集器時,當開始進行收集時,old代的收集過程以下所示:
1,首先jvm根據-XX:CMSInitiatingOccupancyFraction,-XX:+UseCMSInitiatingOccupancyOnly來決定什麼時間開始垃圾收集;
2,若是設置了-XX:+UseCMSInitiatingOccupancyOnly,那麼只有當old代佔用確實達到了-XX:CMSInitiatingOccupancyFraction參數所設定的比例時纔會觸發cms gc;
3,若是沒有設置-XX:+UseCMSInitiatingOccupancyOnly,那麼系統會根據統計數據自行決定何時觸發cms gc;所以有時會遇到設置了80%比例才cms gc,可是50%時就已經觸發了,就是由於這個參數沒有設置的緣由;
4,當cms gc開始時,首先的階段是CMS-initial-mark,此階段是初始標記階段,是stop the world階段,所以此階段標記的對象只是從root集最直接可達的對象;
CMS-initial-mark:961330K(1572864K),指標記時,old代的已用空間和總空間
5,下一個階段是CMS-concurrent-mark,此階段是和應用線程併發執行的,所謂併發收集器指的就是這個,主要做用是標記可達的對象
此階段會打印2條日誌:CMS-concurrent-mark-start,CMS-concurrent-mark
6,下一個階段是CMS-concurrent-preclean,此階段主要是進行一些預清理,由於標記和應用線程是併發執行的,所以會有些對象的狀態在標記後會改變,此階段正是解決這個問題由於以後的Rescan階段也會stop the world,爲了使暫停的時間儘量的小,也須要preclean階段先作一部分工做以節省時間
此階段會打印2條日誌:CMS-concurrent-preclean-start,CMS-concurrent-preclean
7,下一階段是CMS-concurrent-abortable-preclean階段,加入此階段的目的是使cms gc更加可控一些,做用也是執行一些預清理,以減小Rescan階段形成應用暫停的時間
此階段涉及幾個參數:
-XX:CMSMaxAbortablePrecleanTime:當abortable-preclean階段執行達到這個時間時纔會結束
-XX:CMSScheduleRemarkEdenSizeThreshold(默認2m):控制abortable-preclean階段何時開始執行,
即當eden使用達到此值時,纔會開始abortable-preclean階段
-XX:CMSScheduleRemarkEdenPenetratio(默認50%):控制abortable-preclean階段何時結束執行
此階段會打印一些日誌以下:
CMS-concurrent-abortable-preclean-start,CMS-concurrent-abortable-preclean,
CMS:abort preclean due to time XXX
8,再下一個階段是第二個stop the world階段了,即Rescan階段,此階段暫停應用線程,對對象進行從新掃描並標記;
YG occupancy:964861K(2403008K),指執行時young代的狀況
CMS remark:961330K(1572864K),指執行時old代的狀況
此外,還打印出了弱引用處理、類卸載等過程的耗時
9,再下一個階段是CMS-concurrent-sweep,進行併發的垃圾清理
10,最後是CMS-concurrent-reset,爲下一次cms gc重置相關數據結構
11,full gc:
有2種狀況會觸發full gc,在full gc時,整個應用會暫停
A,concurrent-mode-failure:當cms gc正進行時,此時有新的對象要進行old代,可是old代空間不足形成的
B,promotion-failed:當進行young gc時,有部分young代對象仍然可用,可是S1或S2放不下,所以須要放到old代,但此時old代空間沒法容納此。
影響cms gc時長及觸發的參數是如下2個:
-XX:CMSMaxAbortablePrecleanTime=5000
-XX:CMSInitiatingOccupancyFraction=80
解決也是針對這兩個參數來的,根本的緣由是每次請求消耗的內存量過大
解決方式:
A,針對cms gc的觸發階段,調整-XX:CMSInitiatingOccupancyFraction=50,提前觸發cms gc,就能夠緩解當old代達到80%,cms gc處理不完,從而形成concurrent mode failure引起full gc
B,修改-XX:CMSMaxAbortablePrecleanTime=500,縮小CMS-concurrent-abortable-preclean階段的時間
C,考慮到cms gc時不會進行compact,所以加入-XX:+UseCMSCompactAtFullCollection
(cms gc後會進行內存的compact)和-XX:CMSFullGCsBeforeCompaction=4(在full gc4次後會進行compact)參數併發