天天看點

Tenured 區并發垃圾回收器CMS實戰

當使用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