當使用CMS收集器時,當開始進行收集時,old代的收集過程如下所示:
1、首先jvm根據-XX:CMSInitiatingOccupancyFraction,-XX:+UseCMSInitiatingOccupancyOnly來決定什麼時間開CMS始垃圾收集;
1)如果設定了-XX:+UseCMSInitiatingOccupancyOnly,那麼隻有當old代占用确實達到了-XX:CMSInitiatingOccupancyFraction參數所設定的比例時才會觸發cms gc;
2)如果沒有設定-XX:+UseCMSInitiatingOccupancyOnly,那麼系統第一次會根據-XX:CMSInitiatingOccupancyFraction參數所設定的比例觸發,随後會根據統計資料自行決定什麼時候觸發cms gc;
2、當cms gc開始時,首先的階段是CMS-initial-mark,此階段是初始标記階段,是stop the world階段,是以此階段标記的對象隻是從root集最直接可達的對象:
CMS-initial-mark:961330K(1572864K),名額記時,old代的已用空間和總空間
3、其次CMS-concurrent-mark階段,此階段是和應用線程并發執行的,所謂并發收集器指的就是這個,主要作用是标記可達的對象
此階段會列印2條日志:CMS-concurrent-mark-start,CMS-concurrent-mark
4、CMS-concurrent-preclean,此階段主要是進行一些預清理(也屬于concurrent-mark階段),因為标記和應用線程是并發執行的,是以會有些對象的狀态在标記後會改變,
此階段正是解決這個問題因為之後的Rescan階段也會stop the world,為了使暫停的時間盡可能的小
,也需要preclean階段先做一部分工作以節省時間
此階段會列印2條日志:CMS-concurrent-preclean-start,CMS-concurrent-preclean
5、CMS-concurrent-abortable-preclean階段,加入此階段的目的是使cms gc更加可控一些(也屬于concurrent-mark階段),作用也是執行一些預清理,以減少Rescan階段造成應用暫停的時間
此階段涉及幾個參數:
-XX:CMSMaxAbortablePrecleanTime:當abortable-preclean階段執行達到這個時間時才會結束
-XX:CMSScheduleRemarkEdenSizeThreshold(預設2m):控制abortable-preclean階段什麼時候開始執行,
即當eden使用達到此值時,才會開始abortable-preclean階段
-XX:CMSScheduleRemarkEdenPenetration(預設50%):控制abortable-preclean階段什麼時候結束執行
此階段會列印一些日志如下:
CMS-concurrent-abortable-preclean-start,CMS-concurrent-abortable-preclean,
CMS:abort preclean due to time XXX
6、其次是第二個stop the world階段了,即Rescan階段,此階段暫停應用線程,對對象進行重新掃描并标記;
YG occupancy:964861K(2403008K),指執行時young代的情況
CMS remark:961330K(1572864K),指執行時old代的情況
此外,還列印出了弱引用處理、類解除安裝等過程的耗時
7、再下一個階段是CMS-concurrent-sweep,進行并發的垃圾清理;
8、最後是CMS-concurrent-reset,為下一次cms gc重置相關資料結構。
9、full gc:
有2種情況會觸發full gc,在full gc時,整個應用會暫停
1)concurrent-mode-failure:當cms gc正進行時,此時有新的對象要進行old代,但是old代空間不足造成的
2)promotion-failed:當進行young gc時,有部分young代對象仍然可用,但是S1或S2放不下,是以需要放到old代,但此時old代空間無法容納此。
10、影響cms gc時長及觸發的參數是以下2個:
-XX:CMSMaxAbortablePrecleanTime=5000
-XX:CMSInitiatingOccupancyFraction=80
解決也是針對這兩個參數來的,根本的原因是每次請求消耗的記憶體量過大
解決方式:
1)針對cms gc的觸發階段,調整-XX:CMSInitiatingOccupancyFraction=50,提早觸發cms gc,就可以緩解當old代達到80%,cms gc處理不完,進而造成concurrent mode failure引發full gc
2)修改-XX:CMSMaxAbortablePrecleanTime=500,縮小CMS-concurrent-abortable-preclean階段的時間
3)考慮到cms gc時不會進行compact,是以加入-XX:+UseCMSCompactAtFullCollection