JVM配置CMS调优实战笔记

一、背景说明

       由于原有项目未进行JVM配置,全部是用默认JVM配置,在压测过程中TP99惨不忍睹,Young gc使用PS Scavenge,Full gc使用PS MarkSweep

二、JVM基础知识

       1) 虚拟机内存模型:
           程序计数器、虚拟机栈、本地方法栈、JVM堆、方法区(粗略理解包含永久代)

        2) 垃圾收集算法:
            标记-清除、复制、标记-压缩、分代收集算法

        3) jvm堆区分代:
             Eden(年轻代-伊甸园区)、Survivor0(年轻代-存活1区)、Survivor1(年轻代-存活2区)、Old Generation(老年代区)

        4) 垃圾收集器分类:
            Serial : 年轻代、串行、复制算法,默认年轻代收集器, -XX:+UseSerialGC 手动指定年轻代使用Serial收集器 
            Serial Old :老年代、串行、标记-清除、默认老年代收集器、 -XX:+UseSerialGC 手动指定老年代使用Serial收集器
            ParNew :年轻代,并行、复制算法、常用于多核CPU机器上,-XX:+UseParNewGC 手动指定年轻代使用ParNew收集器,可配合CMS收集器使用
            Parallel:年轻代、并行、复制算法、吞吐量优先,-XX:+UseParallelGC手动设置年轻代使用Parallel收集器,-XX:+GCTimeRatio 0~100 手动设置吞吐量大小,-XX:+MaxGCPauseMills 收到设置最大垃圾收集停顿时间
            Parallel Old:老年代、并行、复制算法、吞吐量优先,-XX:+UseParallelOldGC 手动设置年轻代、老年代都使用Parallel收集器
            CMS:老年代、并行、 标记-清除、高响应低延迟,-XX:+UseConcMarkSweepGC 手动设置老年代使用CMS收集器
            G1:使用Region区间贯穿年轻代和老年代,可以将年轻代、老年代理解为标签,而GC回收就相当于是在为每个Region区间进行贴标签的过程。根据回收情况将Region区间定为年轻代和老年代(未在实战中使用过,不做过多介绍)。
            G1相关说明可参见:https://blog.csdn.net/TimerBin/article/details/97148182

         5)Young GC/Full GC
             Young GC:Minor GC 对年轻代空间进行回收,-Xmn1024M 手动指定年轻代内存上限值
              Full GC:Major GC 对老年代空间进行回收,在进行Major GC之前会优先触发Minor GC

三、JVM常用配置参数

        1) -Xmn: 新生代内存上限值
        2) -Xms: 整个堆区初始内存分配的大小
        3) -Xmx: 整个堆区内存分配的最大上限,推荐-Xms和-Xmx设置等同大小,避免动态回收消耗资源
        4) -XX:+HeapDumpOnOutOfMemoryError 当出现OOM时,打印堆转储dump文件
        5) -XX:HeapDumpPath= 指定堆转储dump文件存储路径
        6) -XX:MaxTenuringThreshold=5 : 手动设置对象在新生代中存活年龄(存活次数),默认15次
        7) -XX:SurvivorRatio=6 : Eden区与Survivor0、Survivor1区的大小比值,一般设置为6,Eden:S0:S1=6:1:1
        8) -XX:PretenureSizeThreshold 手动指定对象大小,当对象达到指定大小时直接存放到老年代中,由于新生代大多使用复制算法,为了节省复制消耗
         9) -XX:+UseParNewGC : 手动指定新生代使用 ParNew 收集器
         10) -XX:+UseConcMarkSweepGC : 手动指定老年代使用CMS收集器
         11) -XX:PermSize=512M 指定非堆区域(永久代)初始内存分配大小, JDK 1.7 及以下生效
         12) -XX:MaxPermSize= 1024M 指定非堆区域(永久代)内存分配的最大上限,JDK1.7 及以下生效
         13) -XX:+UseCMSInitiatingOccupancyOnly : Hotspot会根据成本计算决定是否需要执行CMS收集器,可手动设置-XX:+UseCMSInitiatingOccupancyOnly关闭计算策略,强制使用CMS 收集器
         14)  -XX:+CMSClassUnloadingEnabled : 手动指定CMS 收集器对非堆区域永久代进行回收,默认永久代不回收
         15) -XX:CMSInitiatingOccupancyFraction=80 : 手动指定当老年代已用空间达到80%时,触发老年代回收(默认92%)
         16) -XX:CMSInitiatingPermOccupancyFraction=80  : 手动指定当永久代已用空间达到80%时,触发永久代回收(默认92%)
         17) -XX:+DisableExplicitGC : 手动配置禁止使用外部调用System.gc 来进行触发垃圾回收
         18) -XX:+UseCMSCompactAtFullCollection : 在进行Full GC时对内存进行压缩,JDK1.6以前不需要配置,默认开启
         19) -XX:CMSFullGCsBeforeCompaction=2 : 与-XX:+UseCMSCompactAtFullCollection 关联使用标识着每经过多少次Full GC 触发对内存进行一次压缩,默认是0次
          20) -XX:-CMSParallelRemarkEnabled : 手动配置开启并行标记,节省年轻代标记时间,JDK1.6以前不需要配置,默认开启
          21) -Xnoclassgc  : 关闭CLASS的垃圾回收功能,默认20分钟这个class未被使用,虚拟机会卸载这个类。再次使用时重新加载

四、JVM配置小记

linux机器配置:4核8G

问题一

原有JVM配置参数:

-XX:PermSize=512M -XX:MaxPermSize=1024M -XX:+HeapDumpOnOutOfMemoryError -XX:+DisableExplicitGC 

遇到的问题:

  • full gc 执行次数较多,影响用户体验
  • 在full gc执行过程中,导致sql执行超时,被数据库慢SQL命中

可能的原因:

  • 使用默认年轻代和老年代回收器,串行GC,stop-the-world时间较长
  • 使用了默认的存活次数15,增加了在Eden和Survivor区进行复制回收成本
  • 年轻代大小或者年轻代中Eden区与Survivor0、Survivor1空间分配不合理。如果Eden区太小会导致大于Eden区一半对象直接储存到老年代,增加老年代的使用情况

优化后配置:

-Xmx6144M -Xms6144M -XX:PermSize=512M -XX:MaxPermSize=1024M -XX:+HeapDumpOnOutOfMemoryError -XX:+DisableExplicitGC -XX:SurvivorRatio=6 -XX:MaxTenuringThreshold=5 -XX:+UseParNewGC -XX:+UseConcMarkSweepGC

问题二

使用问题一优化后JVM配置:

遇到的问题:

  • yong gc 次数增多,full gc次数近乎为零
  • 由于full gc次数减少,随时间推移,堆内存使用量会持续增长,触发堆内存使用情况报警,目前配置的堆内存使用90%就会报警。

可能的原因:

  • full gc执行次数减少,导致老年代未进行回收
  • 未开启永久点缓存回收

优化后配置:

 -Xmx6144M -Xms6144M -XX:PermSize=512M -XX:MaxPermSize=1024M -XX:+HeapDumpOnOutOfMemoryError -XX:+DisableExplicitGC -XX:SurvivorRatio=6 -XX:MaxTenuringThreshold=5 -XX:+UseParNewGC -XX:+UseConcMarkSweepGC -XX:+UseCMSInitiatingOccupancyOnly  -XX:+CMSClassUnloadingEnabled -XX:CMSInitiatingOccupancyFraction=85   -XX:CMSInitiatingPermOccupancyFraction=85

五、总结

    没有最优的JVM配置,只有最适合的JVM配置,需要结合系统的类型(worker任务、MQ消费、对外接口、WEB平台)和对JVM回收情况的监控,逐步对JVM配置进行调优,持久观察优化,方能配置适合自己系统的最佳JVM配置

 

你可能感兴趣的:(java)