JVM使用了CMS GC時的一些默認(rèn)情況

簡書 占小狼,轉(zhuǎn)載請注明原創(chuàng)出處,謝謝!

為了滿足高性能、低延遲的要求,大部分應(yīng)用都采用CMS算法作為服務(wù)端的垃圾收集器,而在HotSpot的實(shí)現(xiàn)中,針對CMS算法,對于一些參數(shù)進(jìn)行了一系列的重新定制,所以在使用-XX+:UseConcMarkSweepGC時,下面幾點(diǎn)是需要注意的。

-Xmx2g 
-Xms2g 
-XX:+UseConcMarkSweepGC

假設(shè)使用上述參數(shù),只設(shè)置了堆的大小,并且使用了CMS,應(yīng)用啟動后,堆的相關(guān)默認(rèn)參數(shù)如下:

新生代的初始和最大容量為332.75M,為什么是這個數(shù)字?一切疑團(tuán)要從源碼解開。

因?yàn)樵O(shè)置了UseConcMarkSweepGC,在JVM啟動的時候,會執(zhí)行如下邏輯進(jìn)行一些特殊設(shè)置,位于Arguments::set_cms_and_parnew_gc_flags().

1、UseParNewGC

如果UseParNewGC為默認(rèn)值false,則會設(shè)置為true,所以不需要顯示的-XX:+UseParNewGC.

2、ParallelGCThreads

如果沒有設(shè)置ParallelGCThreads,默認(rèn)為0,會根據(jù)cpu數(shù)量重新計(jì)算,大概算法如下:

int ncpus = (unsigned int) os::active_processor_count();
ParallelGCThreads = (ncpus <= 8) ? ncpus : (8 + ((ncpus - 8) * 5) / 8);

如果是單核cpu的話,那UseParNewGC會被重新設(shè)置為false,ParallelGCThreads也會被重新設(shè)置為0

3、NewSize and MaxNewSize

新生代合適的最大值計(jì)算邏輯如下:

const size_t preferred_max_new_size_unaligned =
    MIN2(max_heap/(NewRatio+1), ScaleForWordSize(young_gen_per_worker * parallel_gc_threads));
    
  size_t preferred_max_new_size =
    align_size_up(preferred_max_new_size_unaligned, os::vm_page_size());

如果不是CMS,新生代默認(rèn)的最大值是max_heap/(NewRatio+1),即最大堆的1/3,這里當(dāng)然需要重新計(jì)算,其中young_gen_per_worker默認(rèn)是64M,parallel_gc_threads為4(本機(jī)只有4個cpu),ScaleForWordSize函數(shù)實(shí)現(xiàn)如下:

#define ScaleForWordSize(x) align_size_down_((x) * 13 / 10, HeapWordSize)

計(jì)算出來332.8M,因?yàn)橐M(jìn)行地址對齊,所以和圖中所示差不多(332.75M)

如果沒有設(shè)置NewSize,NewSize和MaxNewSize都會設(shè)置成preferred_max_new_size,否則MaxNewSize會被賦值一個較大值(NewSize和preferred_max_new_size較大值)

如果沒有設(shè)置OldSize,OldSize一般被設(shè)置成NewSize的兩倍(本來默認(rèn)就是2倍的關(guān)系),具體算法是:

if (FLAG_IS_DEFAULT(OldSize)) {
    if (max_heap > NewSize) {
      FLAG_SET_ERGO(uintx, OldSize, MIN2(NewRatio*NewSize, max_heap - NewSize));
      if (PrintGCDetails && Verbose) {
        // Too early to use gclog_or_tty
        tty->print_cr("CMS ergo set OldSize: " SIZE_FORMAT, OldSize);
      }
    }
  }

其實(shí),整個過程還是蠻繞的。

4、MaxTenuringThreshold

MaxTenuringThreshold是對象晉升到老年代的最大年齡,默認(rèn)是15,但是在CMS的情況下,可能會被設(shè)置成一個更小的值6

if (FLAG_IS_DEFAULT(MaxTenuringThreshold) &&
      FLAG_IS_DEFAULT(SurvivorRatio)) {
    FLAG_SET_ERGO(intx, MaxTenuringThreshold, tenuring_default);
  }

前提:沒有改變MaxTenuringThreshold(15)和SurvivorRatio(8)的默認(rèn)值


其它和CMS有關(guān)的情況:

5、ExplicitGCInvokesConcurrent

使用該參數(shù),可以避免System.gc()的FGC,使用并發(fā)的CMS進(jìn)行垃圾回收

6、GCLockerInvokesConcurrent

慎用,具體情況可以看看《慎重!是否使用GCLockerInvokesConcurrent》?

7、concurrent mode failed

只有CMS算法中才會出現(xiàn)concurrent mode failed,一旦它的出現(xiàn),意味著有一次耗時很長的FGC了,更具體的可以查看《關(guān)于CMS垃圾收集算法的一些疑惑》

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

友情鏈接更多精彩內(nèi)容