JVM如何调优

 

上期我们介绍了JVM内存模型及垃圾回收的算法 juejin.cn/post/691347…

这里我们对JVM GC的性能调优参数进行一个整理,通过调节参数来保证我们系统的可靠性。

  • -Xms3550m:初始化堆大小,一开始使用的内存大小,如果超出该大小就会自动扩容;

  • -Xmx3550m:最大堆大小,初始化系统就会分配,虽然一开始使用的是初始堆大小,但是可以根据情况动态扩容,但是不能超过最大堆大小,否则会抛出outOfMemoryError;

  • -Xmn:设置年轻代的大小;

  • -XX:SurvivorRatio=4:年轻代中Eden区与一个Survivor区的比值。例如是设置为4则代表两个Survivor和Eden的比值为2:4,一个Survivor占用的整个年轻代的1/6;

  • -XX:NewRatio=3:新生代:老年代1:3;

  • -XX:MetaspaceSize=256m 元空间初始值(这个是JDK8以后的参数,因为JDK8移除了永久代取而代之的是元空间,如果是JDK7或者是以前的版本,可以使用-XX:PermSize=256m以及XX:MaxPermSize=512m);

  • -XX:MaxMetaspaceSize=512m 元空间最大值(注意这里是堆外内存,他是不计入堆大小内存中的);

  • -Xss=1m:设置每个线程的堆栈大小,减小这个值意味着同样的内存空间可以生成更多的线程。

收集器的选择

  • -XX:+UseSerialGC:使用Serial(新生代)+Serial Old(老年代)的组合(虚拟机运行在Client模式下的默认值);

  • -XX:+UserParNewGC:使用ParNew(新生代) + Serial Old(老年代)的收集器组合;

  • -XX:+UseParallelGC:使用Parallel Scavenge(新生代) + Serial Old(老年代)的收集器组合 ;

  • -XX:+UseParallelOldGC:使用Parallel Scavenge(新生代) + Parallel Old(老年代)的收集器组合;

  • -XX:+UseConcMarkSweepGC:使用ParNew + CMS + Serial Old的收集器组合进行内存回收。Serial Old收集器是作为CMS收集器出现 Concurrent Mode Failure失败后的后备收集器使用;

  • -XX:+UseG1GC:使用G1垃圾收集器(JDK9后Server模式默认值);

  • -XX:+UseZGC:使用ZGC收集器;

  • -XX:UseShenandoahGC:使用Shenandoah收集器。

收集器的参数设置

  • -XX:PretenureSizeThreshold:直接晋升到老年代的对象大小,当对象的大小超过这个值就会直接跳过新生代进入到老年代当中;

  • -XX:MaxTenuringThreshold=0:设置垃圾最大年龄。如果设置为0的话,则年轻代对象不经过Survivor区直接进入老年代,这样对于老年代比较多的应用,可以提高其效率。如果将此值设置为一个较大的值,则年轻代对象会在Survivor区进行多次复制,这样可以增加对象在年轻代的存活时间,增加其在年轻代就被回收的概率;

  • -XX:UseAdapticeSizePolicy:动态调整java堆中各个区域的大小以及进入老年代的年龄;

  • -XX:HandlePromotionFailure:是否允许分配担保失败,即老年代的剩余空间不足以应付新生代的整个Eden和Survivir区的所有对象都存活的极端情况;

  • -XX:ParallelGCThreads=n:设置并行收集器收集时使用的CPU数。并行收集线程数;

  • -XX:MaxGCPauseMillis=n:设置并行收集最大暂停时间(仅在使用Parallel Scavenge和G1收集器的时候生效);

  • -XX:GCTimeRatio=n:设置垃圾回收时间占程序运行时间的百分比(仅在使用Parallel Scavenge收集器的时候生效);

  • -XX:CMSInitiationOccupancyFraction:设置CMS收集器在老年代空间被使用多少后触发垃圾收集,默认值为68%(仅在使用CMS收集器的时候生效);

  • -XX:UseCMSCompactAtFullCollection:设置CMS收集器在完成垃圾收集后是否要进行一次内存碎片整理(仅在使用CMS收集器的时候生效,在JDK9开始废弃);

  • -XX:CMSFullGCsBeforeCompaction:设置CMS收集器在进行若干次垃圾收集器再启动一次内存碎片整理(仅在使用CMS收集器的时候生效,在JDK9开始废弃);

  • -XX:ConcGCThreads=n:设置并发垃圾收集器使用的线程的数量;

  • -XX:NewSizePecent:新生代最小值,默认值是5%(G1);

  • -XX:MaxNewSizePecent:新生代最大值,默认值是60%(G1);

  • -XX:G1ReservePercent=n:设置堆内存保留为假天花板的总量,以降低提升失败的可能性. 默认值是 10(G1);

  • -XX:G1HeapRegionSize=n:使用G1时java堆会被分为大小统一的区域(region),此参数就是设置每个heap区的大小,其最小为1Mb,最大为32Mb(G1);

  • InitiatingHeapOccupancyPercent:设置触发标记周期java堆占用率阈值,默认值是45%,这里的java比是指non_young_capacity_bytes,包括old+humongous;

  • ShenandoahGCHeuristics:Shenandoah何时启动一次GC过程(Shenandoah收集器特有);

  • UseNUMA:启动NUMA内存分配支持,目前只有Parallel和ZGC支持。

Minor GC以及 Major GC

  • 大多数情况下对象在新生代的Eden区中分配,当Eden区没有足够空间进行分配的时候,虚拟机将发起一次Minor GC。新生代的Minor GC非常的频繁,一般回收速度也比较快。在发生Minor GC前,虚拟机会先检查老年代最大可用的连续空间是否大于新生代大对象的总大小或者是历次晋升老年代的平均对象大小,如果不满足的话就会进行Full GC;

  • Major GC是指发生在老年代的GC,出现Major  GC经常会伴随着最少一次的Minor GC,Major GC的速度一般会比Minor  GC的慢10倍以上。

对象进入老年代的条件

  • 通过前面介绍的XX:PretenureSizeThreshold参数判断对象是否是大对象,如果是的话该对象会直接进入老年代;

  • 年龄大于前面介绍的MaxTenuringThreshold的对象会晋升到老年代;

  • 如果Survivor空间中相同年龄所有对象大小的总和大于Survivor空间的一半,年龄大于或者等于该年龄的对象也会直接进入到老年代

导致Full GC的原因

  • 老年代被写满;

  • 持久代Pemannet Generation空间不足;

  • 统计得到的Young GC晋级到老年代的大小大于老年代的剩余空间;

  • System.gc()被显示调用。

调优的规则

  • 根据不同的业务情况调优的参数会有不一样,这个可以通过性能监控工具进行监控然后做出准确的判断。比如需要大量创建短暂生命周期的对象的话可以适当调整新生代的空间大小,减小Minor GC的次数,因为对于虚拟机来说。复制对象的成本要远远高于扫描的成本。所以,单次Minor GC花费的时间更多取决于GC后存活的对象的数量,而非Eden区的大小,所以增大空间能提高效率;

  • 如果发现Major GC的次数比较多,可以增加老年代的大小,同时也要观察在进行Major GC后是否会清理掉较多的空间,如果是的话说明老年代有很多并非长期存活的对象,可以考虑增大-XX:MaxTenuringThreshold的值,避免对象太早进入老年代。

猜你喜欢

转载自blog.csdn.net/Baron_ND/article/details/112413434