CMS默认新生代是多大?
简书 涤生。
转载请注明原创出处,谢谢!
如果读完觉得有收获的话,欢迎点赞加关注。
介绍
首先抛个问题给大家,看下面这段JVM参数
-Xmx2g -Xms2g -XX:+UseConcMarkSweepGC
大家猜一猜这样的JVM参数配置,新生代多大呢?心想这还不简单吗,NewRatio默认为2,也就是新生代与老年代的比例是1:2,那新生代大小应该是2048M/3= 672M。真的是这样吗?
jmap堆的配置
结果居然是332.75M。
原因
要说具体原因只能撸源码了。
我们从Arguments(是用来解析jvm参数)类的set_cms_and_parnew_gc_flags这个方法说起,看方法名也知道是对cms和parnew GC方式的参数设置。
MaxNewSize设置
可以看到里面有段MaxNewSize的设置(提示1),在MaxNewSize和NewRatio都是默认配置时,MaxNewSize值为preferred_max_new_size,preferred_max_new_size这又是什么呢?可以看提示2,align_size_up主要是字节对齐用的,可以不用关系细节,所以preferred_max_new_size主要取决于preferred_max_new_size_unaligned,我们再看提示3,preferred_max_new_size_unaligned的值为
MIN2(max_heap/(NewRatio+1), ScaleForWordSize(young_gen_per_worker * parallel_gc_threads)),也就是取max_heap/(NewRatio+1)和ScaleForWordSize(young_gen_per_worker * parallel_gc_threads)中较小的那个,max_heap/(NewRatio+1)这个我们都了解,ScaleForWordSize又是什么呢?
ScaleForWordSize
这里我们是64位的,align_size_down_这个也是字节对齐的,所以ScaleForWordSize返回值约为(x) * 13 / 10,也就是young_gen_per_worker * parallel_gc_threads*13/10,所以我们再看看young_gen_per_worker和parallel_gc_threads的取值,
young_gen_per_worker = CMSYoungGenPerWorker,CMSYoungGenPerWorker在另一块代码中有定义,跟硬件相关x86机器为64M,而parallel_gc_threads的值呢?
parallel_gc_threads =(ParallelGCThreads == 0 ? 1 : ParallelGCThreads),所以我们得看ParallelGCThreads
ParallelGCThreads
可知,ParallelGCThreads在没有设置的情况下会设置成parallel_worker_threads方法返回值,我们接着看parallel_worker_threads方法。
parallel_worker_threads
看上图1,2,3最终由3进行计算,ncpus是cpu的核数,测试机器是4核,所以ncpus为4,按照上面的计算,所以ParallelGCThreads为4。
所以绕了半天,ScaleForWordSize的值大约是64M * 4 * 13 / 10=332.8M,再做下对齐就得到332.75M了;max_heap/(NewRatio+1)的值为2048M/3= 672M,而新生代的值取了较小的ScaleForWordSize,故为332.75M。不知道cms为什么要这么做?
总结
看到上面的过程,是不是有点奔溃。既然新生代大小有不确定性,那还是手动设置下-XX:NewSize、 -XX:MaxNewSize或者-xmn,免得遇到一些奇怪的GC,让你大吃一惊。
作者:涤生_YinQi
链接:https://www.jianshu.com/p/832fc4d4cb53