当前位置: 首页 > 科技观察

JVM新生代和老年代的默认比例真的是1-2吗?

时间:2023-03-15 16:09:15 科技观察

图片来自Pexels[.com原稿]业界普遍的认知如下图所示,是否正确?结论先:如果你在启动进程的时候不加任何JVM调优参数,也就是默认选项,那么不管你用的是哪个JDK版本?新生代和老年代的默认比例不再是1:2!Eden、SurvivorFrom、SurvivorTo的默认比例不再是8:1:1!原因慢慢来了。01先说JDK版本从JDK1.5开始,公开版本号改为JDK5命令方式。只有开发版本号会遵循JDK1.5命令方式。截至目前,最新的JDK版本是2021年3月发布的JDK16。本文的范围将涵盖所有JDK版本,但以JDK8为主线,因为JDK8目前市场占有率最高,而JDK8属于LTS版本(LongTermSupport,长期支持)。JDK8发布于2014年3月,JDK8承诺的最后支持日期是:2030年12月。JDK8之后的下一个LTS版本是2018年9月发布的JDK11。JDK11承诺的最后支持日期是:2026年9月,没那么长作为JDK8的支持。下一个LTS版本是JDK17,将于2021年9月发布。JDK版本的发布从JDK9变为严格的基于时间的模型,每六个月发布一个新版本,每三年发布一个LTS版本。02另外GC收集器的说明如下:①根据JDK的最新版本,除了上面提到的9个GC收集器外,还有一个是JDK11引入的Epsilon收集器。也就是说,目前历史上有10个GC收集器,Epsilon收集器不进行任何垃圾收集工作(ANo-OpGarbageCollector)。例如,对于性能测试等希望排除GC性能影响且流程执行生命周期较短的特殊场景。所以它超出了本文的范围。②ZGC和Shenandoah的设计目标相似,都是针对G1的不足。只有ZGC是由Oracle发起的,而Shenandoah是由RedHat发起的,所以官方的强调会略有不同。另外,直到JDK16,这2个收集器依然没有取代G1成为默认选项。虽然官方宣称这两个收集器可以兼顾吞吐量和响应时间,但每个JDK版本都在不断优化,尚未成熟。③JDK8的“JEP173:RetireSomeRarely-UsedGCCombinations”已经废弃了-XX:+UseParNewGC组合。有关详细信息,请参阅:http://openjdk.java.net/jeps/173。原因:很少使用的组合。④JDK9的《JEP291:DeprecatetheConcurrentMarkSweep(CMS)GarbageCollector》中不再推荐-XX:+UseConcMarkSweepGC组合中的CMS收集器。它已在JDK14中的“JEP363:删除并发标记清除(CMS)垃圾收集器”中被弃用。详见:http://openjdk.java.net/jeps/291、http://openjdk.java.net/jeps/363。原因是:G1已经成为默认收集器。与CMS一样,G1优先考虑响应时间。G1的使命是取代CMS。限于篇幅,本文不再详述各个GC收集器的具体作用和原理。03哪个参数决定了新生代和老年代的默认比例?NewRatio,默认值:2,也就是说默认的新生代和老年代的比例是1:2。如下图所示,不仅JDK8的NewRatio默认值是2,JDK16最新版本的NewRatio默认值依然是2。SurvivorRatio,默认值:8,效果一样。NewRatio和SurvivorRatio的默认值虽然没有问题,但实际上不一定生效。下面将介绍具体的验证分析过程。04验证分析下面的验证分析过程是基于JDK8的。①启动进程时不要添加任何JVM参数。默认值:-XX:+UseParallelGC,ParallelScavenge+ParallelOld的GC收集器组合。如下图,确实NewRatio=2,NewSize=42.0MB,OldSize=84.0MB,符合1:2。但是看HeapUsage的细节,EdenSpacecapacity=306.5MB,比PSOldGenerationcapacity=130.5MB还多。另外,Eden、SurvivorFrom、SurvivorTo的比例显然不是8:1:1。为什么会这样?②尝试使用其他GC收集器参数?-XX:+UseSerialGC:Serial+SerialOldGC收集器组合。详见HeapUsage,多了一块NewGeneration=Eden+1SurvivorSpace。如果再加一个SurvivorSpace(FromSpace或ToSpace),刚好是42.0MB,和OldSize的比例是1:2,没有问题。另外,Eden、SurvivorFrom、SurvivorTo的比例显然也是8:1:1。-XX:+UseConcMarkSweepGC:ParNew+CMS的GC收集器组合。看HeapUsage的细节,效果和-XX:+UseSerialGC基本一样,没问题。-XX:+UseG1GC:G1收集器。查看HeapUsage的详细信息,不符合NewRatio默认的1:2比例。此外,FromSpace和ToSpace也消失了。为什么会这样?其他组合:Deprecate或Remove,无参考。③原因分析(1)在JDK1.3之前,-XX:+UseSerialGC是收集器的唯一选择。当时JVM默认的新生代和老年代的比例确实是1:2。(2)-XX:+UseConcMarkSweepGC类似于-XX:+UseSerialGC的多线程版本,都有代码帧的复用,所以性能是一样的。(3)-XX:+UseSerialGC、-XX:+UseG1GC、-XX:+UseZGC、-XX:+UseShenandoahGC,没有使用传统的GC代码框架,所以性能不同。(4)基于以上几点,值得注意的是JDK7U4之前的-XX:+UseParallelGC的老年代GC是SerialOld。其实SerialOld的代码框架并没有被复用。-XX:+UseParallelGC的老年代GC叫做:PSMarkSweep。它的实现原理和SerialOld很接近,所以很多资料包括官方的都叫SerialOld。.(5)UseAdaptiveSizePolicy参数很重要!该参数默认开启,直到最新版本的JDK16仍然开启。该参数对是否启用-XX:+UseSerialGC和-XX:+UseConcMarkSweepGC没有影响。该参数对应GC自适应调整策略(GCErgonomics)。如果启用,JVM会根据系统的运行情况动态调整一些参数,包括:新生代与老年代的比例。Eden、SurvivorFrom、SurvivorTo的比例;大对象直接进入老年代的阈值等,达到吞吐量优先的目的。④尝试关闭UseAdaptiveSizePolicy参数?-XX后面有加号的参数开启,-XX后面有减号的参数关闭。启动进程时添加JVM参数-XX:-UseAdaptiveSizePolicy。GC收集器保持默认:-XX:+UseSerialGC,ParallelScavenge+ParallelOld的组合。查看HeapUsage详情,一切正常,新生代与老年代的比例为1:2。Eden、SurvivorFrom、SurvivorTo的比例也是8:1:1。⑤UseAdaptiveSizePolicy参数相关源码分析从http://hg.openjdk.java.net获取热点源码。新生代-XX:+UseParallelGC在psScavenge.cpp中实现,老年代在psOldGen.cpp中实现,均在hotspot\src\share\vm\gc_implementation\parallelScavenge目录下。如下图所示,当默认启用UseAdaptiveSizePolicy时,则进入动态调整的处理逻辑。如下图,进入动态调整的处理逻辑后就是核心代码heap→resize_young_gen。⑥最新的-XX:+UseZGC或者-XX:+UseShenandoahGC呢?G1收集器同样遵循分代收集理论,但是它将连续的Java堆划分为大小相等的区域,不区分新生代和老年代,每个Region将作为新生代或老年代的空间需要。G1依然保留了新生代和老年代,新生代也区??分了Eden和Survivor,但是Survivor不再区分From和To。在ZGC和ShenandoahGC的情况下,颠覆的比较彻底,不再区分新生代和老年代,也就是说不再使用分代收集,默认比例的问题没有意义。05结语①NewRatio,默认值为2,这个是千古不变的,即使是最新的JDK16版本也是如此。毕竟,最古老和最重要的-XX:+UseSerialGC从未被Deprecate或Remove。它仍然是客户端模式下的默认选项。②JVM新生代和老年代的默认比例与选择的GC收集器有关!不仅相关,而且决定了新生代和老年代的概念是否存在。③由于-XX:+UseParallelGC取代了-XX:+UseSerialGC作为默认选项,JVM新生代和老年代的默认比例不再是1:2,而是可以动态调整比例。比如目前市场占有率最高的是JDK8。④从JDK9开始,-XX:+UseG1GC取代-XX:+UseParallelGC成为默认选项。或者-XX:+UseZGC或者-XX:+UseShenandoahGC可能会成为未来的默认选项(毕竟设计目标是针对G1的缺点)。JVM默认的新生代和老年代的比例是1:2就更不可能了,甚至可能不存在新生代和老年代的概念。所以JVM默认新生代和老年代的比例是1:2,错了10年。面试官和求职者总是不经深思熟虑就“好理解”!希望这篇文章能改变业界的一些误解。另外,虽然被业界誉为:JVM向日葵宝典&《深入理解 Java 虚拟机》高级JVM教材级别,但书中很多论点没有及时更新,可能误导读者。与其相信书本,不如没有书本。用死记硬背的面试问题来糊弄求职者的面试官是耍流氓。作者:大黄蜂简介:曾供职于华为、腾讯等大型互联网公司,2018年5月加入独角兽公司akulaku担任技术管理岗位。在分期、理财等核心系统的架构设计方面具有丰富的实践经验。精通Redis和JVM,重视底层原理,对高级用法、协议、源码等有深入研究,并且有自己独特的团队管理理念,另辟蹊径,专注研究和发展质量与效益,为公司培养了众多年轻有潜力的年轻人,并多次获得各类奖项。编辑:陶佳龙征稿:如有意投稿或求报道,请加编辑微信gordonlonglong【原创稿件,合作网站转载请注明原作者及出处为.com】