程序员必备:JVM核心知识点总结( 七 )

下面介绍一下这两个参数:

  • UseConcMarkSweepGC,表示年轻代使用 ParNew,老年代的用 CMS 垃圾回收器
  • -XX:CMSInitiatingOccupancyFraction 由于 CMS 在执行过程中,用户线程还需要运行,那就需要保证有充足的内存空间供用户使用 。如果等到老年代空间快满了,再开启这个回收过程,用户线程可能会产生“Concurrent Mode Failure”的错误,这时会临时启用 Serial Old 收集器来重新进行老年代的垃圾收集,这样停顿时间就很长了(STW) 。
这部分空间预留,一般在 30% 左右即可,那么能用的大概只有 70% 。参数
-XX:CMSInitiatingOccupancyFraction 用来配置这个比例,但它首先必须配置 -XX:+UseCMSInitiatingOccupancyOnly 参数 。
另外,对于 CMS 垃圾回收器,常用的还有下面的配置参数:
  • -XX:ExplicitGCInvokesConcurrent 当代码里显示的调用了 System.gc(),实际上是想让回收器进行FullGC,如果发生这种情况,则使用这个参数开始并行 FullGC 。建议加上 。
  • -XX:CMSFullGCsBeforeCompaction 默认为 0,就是每次FullGC都对老年代进行碎片整理压缩,建议保持默认 。
  • -XX:CMSScavengeBeforeRemark 开启或关闭在 CMS 重新标记阶段之前的清除(YGC)尝试 。可以降低 remark 时间,建议加上 。
  • -XX:+ParallelRefProcEnabled 可以用来并行处理 Reference,以加快处理速度,缩短耗时 。
CMS 垃圾回收器,已经在 Java14 中被移除,由于它的 GC 时间不可控,有条件应该尽量避免使用 。
针对 Java10(普通 Java 应用在 Java 8 中即可开启 G1),ES 可采用 G1 垃圾回收器 。
G1垃圾收集器,它可以通过配置参数 MaxGCPauseMillis,指定一个期望的停顿时间,使用相对比较简单 。
下面是主要的配置参数:
  • -XX:MaxGCPauseMillis 设置目标停顿时间,G1 会尽力达成 。
  • -XX:G1HeapRegionSize 设置小堆区大小 。这个值为 2 的次幂,不要太大,也不要太小 。如果是在不知道如何设置,保持默认 。
  • -XX:InitiatingHeapOccupancyPercent 当整个堆内存使用达到一定比例(默认是45%),并发标记阶段就会被启动 。
  • -XX:ConcGCThreads 并发垃圾收集器使用的线程数量 。默认值随 JVM 运行的平台不同而不同 。不建议修改 。
JVM 支持非常多的垃圾回收器,下面是最常用的几个,以及配置参数:
  • -XX:+UseSerialGC 年轻代和老年代都用串行收集器
  • -XX:+UseParallelGC 年轻代使用 ParallerGC,老年代使用 Serial Old
  • -XX:+UseParallelOldGC 新生代和老年代都使用并行收集器
  • -XX:+UseG1GC 使用 G1 垃圾回收器
  • -XX:+UseZGC 使用 ZGC 垃圾回收器
额外配置我们再来看下几个额外的配置 。
-Xss1m-Xss设置每个 Java 虚拟机栈的容量为 1MB 。这个参数和 -XX:ThreadStackSize是一样的,默认就是 1MB 。
-XX:-OmitStackTraceInFastThrow把 - 换成 +,可以减少异常栈的输出,进行合并 。虽然会对调试有一定的困扰,但能在发生异常时显著增加性能 。随之而来的就是异常信息不好排查,ES 为了找问题方便,就把错误合并给关掉了 。
-Djava.awt.headless=trueHeadless 模式是系统的一种配置模式,在该模式下,系统缺少了显示设备、键盘或鼠标 。在服务器上一般是没这些设备的,这个参数是告诉虚拟机使用软件去模拟这些设备 。
-Djava.locale.providers=COMPAT-Dfile.encoding=UTF-8-Des.networkaddress.cache.ttl=60-Des.networkaddress.cache.negative.ttl=10-Dio.netty.noUnsafe=true-Dio.netty.noKeySetOptimization=true-Dio.netty.recycler.maxCapacityPerThread=0-Dlog4j.shutdownHookEnabled=false-Dlog4j2.disable.jmx=true-Djava.io.tmpdir=${ES_TMPDIR}-Djna.nosys=true上面这些参数,通过 -D 参数,在启动一个 Java 程序时,设置系统属性值,也就是在 System 类中通过getProperties()得到的一串系统属性 。
这部分自定义性比较强,不做过多介绍 。
其他调优以上就是 ES 默认的 JVM 参数配置,大多数还是比较基础的 。在平常的应用服务中,我们希望得到更细粒度的控制,其中比较常用的就是调整各个分代之间的比例 。