JVM使用了CMS GC时的一些默认情况

作者: 美团Java | 来源:发表于2017-11-26 14:17 被阅读1143次

    简书 占小狼,转载请注明原创出处,谢谢!

    为了满足高性能、低延迟的要求,大部分应用都采用CMS算法作为服务端的垃圾收集器,而在HotSpot的实现中,针对CMS算法,对于一些参数进行了一系列的重新定制,所以在使用-XX+:UseConcMarkSweepGC时,下面几点是需要注意的。

    -Xmx2g 
    -Xms2g 
    -XX:+UseConcMarkSweepGC
    

    假设使用上述参数,只设置了堆的大小,并且使用了CMS,应用启动后,堆的相关默认参数如下:

    新生代的初始和最大容量为332.75M,为什么是这个数字?一切疑团要从源码解开。

    因为设置了UseConcMarkSweepGC,在JVM启动的时候,会执行如下逻辑进行一些特殊设置,位于Arguments::set_cms_and_parnew_gc_flags().

    1、UseParNewGC

    如果UseParNewGC为默认值false,则会设置为true,所以不需要显示的-XX:+UseParNewGC.

    2、ParallelGCThreads

    如果没有设置ParallelGCThreads,默认为0,会根据cpu数量重新计算,大概算法如下:

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

    如果是单核cpu的话,那UseParNewGC会被重新设置为false,ParallelGCThreads也会被重新设置为0

    3、NewSize and MaxNewSize

    新生代合适的最大值计算逻辑如下:

    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,新生代默认的最大值是max_heap/(NewRatio+1),即最大堆的1/3,这里当然需要重新计算,其中young_gen_per_worker默认是64M,parallel_gc_threads为4(本机只有4个cpu),ScaleForWordSize函数实现如下:

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

    计算出来332.8M,因为要进行地址对齐,所以和图中所示差不多(332.75M)

    如果没有设置NewSize,NewSize和MaxNewSize都会设置成preferred_max_new_size,否则MaxNewSize会被赋值一个较大值(NewSize和preferred_max_new_size较大值)

    如果没有设置OldSize,OldSize一般被设置成NewSize的两倍(本来默认就是2倍的关系),具体算法是:

    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);
          }
        }
      }
    

    其实,整个过程还是蛮绕的。

    4、MaxTenuringThreshold

    MaxTenuringThreshold是对象晋升到老年代的最大年龄,默认是15,但是在CMS的情况下,可能会被设置成一个更小的值6

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

    前提:没有改变MaxTenuringThreshold(15)和SurvivorRatio(8)的默认值


    其它和CMS有关的情况:

    5、ExplicitGCInvokesConcurrent

    使用该参数,可以避免System.gc()的FGC,使用并发的CMS进行垃圾回收

    6、GCLockerInvokesConcurrent

    慎用,具体情况可以看看《慎重!是否使用GCLockerInvokesConcurrent》�

    7、concurrent mode failed

    只有CMS算法中才会出现concurrent mode failed,一旦它的出现,意味着有一次耗时很长的FGC了,更具体的可以查看《关于CMS垃圾收集算法的一些疑惑》

    相关文章

      网友评论

      • a072fa038320:狼哥 图一的默认参数 是什么命令出来的?
        美团Java:@马丁路德没有gold jstat
      • 不改青铜本色:想请问个问题,多线程执行会导致指令重排序,那为什么还能在程序中打断点,打断点的话不就意味着程序是在顺序执行吗

      本文标题:JVM使用了CMS GC时的一些默认情况

      本文链接:https://www.haomeiwen.com/subject/fezcpxtx.html