大型电商系统后端现在一般都是拆分为多个子系统部署的,比如,商品系统,库存系统,订单系统,促销系统,会员系 统等等。 我们这里以比较核心的订单系统为例
    image.png
    对于8G内存,我们一般是分配4G内存给JVM,正常的JVM参数配置如下:
    ‐Xms3072M 最小堆内存
    ‐Xmx3072M 最大堆内存
    ‐Xss1M 栈内存
    ‐XX:MetaspaceSize=256M 方法区最小内存
    ‐XX:MaxMetaspaceSize=256M 方法区最大内存
    ‐XX:SurvivorRatio=8 年轻代内存比例
    这样设置可能会由于动态对象年龄判断原则导致频繁full gc。
    于是我们可以更新下JVM参数设置:
    ‐Xms3072M 最小堆内存
    ‐Xmx3072M 最大堆内存
    ‐Xmn2048M 年轻代总内存
    ‐Xss1M 栈内存
    ‐XX:MetaspaceSize=256M 方法区最小内存
    ‐XX:MaxMetaspaceSize=256M 方法区最大内存
    ‐XX:SurvivorRatio=8 年轻代内存比例
    image.png
    这样就降低了因为对象动态年龄判断原则导致的对象频繁进入老年代的问题,其实很多优化无非就是让短期存活的对象 尽量都留在survivor里,不要进入老年代,这样在minor gc的时候这些对象都会被回收,不会进到老年代从而导致full gc。

    对于对象年龄应该为多少才移动到老年代比较合适,本例中一次minor gc要间隔二三十秒,大多数对象一般在几秒内就 会变为垃圾,完全可以将默认的15岁改小一点,比如改为5,那么意味着对象要经过5次minor gc才会进入老年代,整个 时间也有一两分钟了,如果对象这么长时间都没被回收,完全可以认为这些对象是会存活的比较长的对象,可以移动到 老年代,而不是继续一直占用survivor区空间。
    对于多大的对象直接进入老年代(参数-XX:PretenureSizeThreshold),这个一般可以结合你自己系统看下有没有什么大对象 生成,预估下大对象的大小,一般来说设置为1M就差不多了,很少有超过1M的大对象,这些对象一般就是你系统初始 化分配的缓存对象,比如大的缓存List,Map之类的对象。 可以适当调整JVM参数如下:
    ‐Xms3072M ‐Xmx3072M ‐Xmn2048M ‐Xss1M ‐XX:MetaspaceSize=256M ‐XX:MaxMetaspaceSize=256M ‐XX:SurvivorRatio=8 2 ‐XX:MaxTenuringThreshold=5 ‐XX:PretenureSizeThreshold=1M

    对于JDK8默认的垃圾回收器是-XX:+UseParallelGC(年轻代)和-XX:+UseParallelOldGC(老年代),如果内存较大(超过4个G,只是经验 值),系统对停顿时间比较敏感,我们可以使用ParNew+CMS(-XX:+UseParNewGC -XX:+UseConcMarkSweepGC) 对于老年代CMS的参数如何设置我们可以思考下,首先我们想下当前这个系统有哪些对象可能会长期存活躲过5次以上 minor gc最终进入老年代。

    无非就是那些Spring容器里的Bean,线程池对象,一些初始化缓存数据对象等,这些加起来充其量也就几十MB。 还有就是某次minor gc完了之后还有超过一两百M的对象存活,那么就会直接进入老年代,比如突然某一秒瞬间要处理 五六百单,那么每秒生成的对象可能有一百多M,再加上整个系统可能压力剧增,一个订单要好几秒才能处理完,下一秒 可能又有很多订单过来。

    我们可以估算下大概每隔五六分钟出现一次这样的情况,那么大概半小时到一小时之间就可能因为老年代满了触发一次 Full GC,Full GC的触发条件还有我们之前说过的老年代空间分配担保机制,历次的minor gc挪动到老年代的对象大小 肯定是非常小的,所以几乎不会在minor gc触发之前由于老年代空间分配担保失败而产生full gc,其实在半小时后发生 full gc,这时候已经过了抢购的最高峰期,后续可能几小时才做一次FullGC。 对于碎片整理,因为都是1小时或几小时才做一次FullGC,是可以每做完一次就开始碎片整理,或者两到三次之后再做一 次也行。

    综上,只要年轻代参数设置合理,老年代CMS的参数设置基本都可以用默认值,具体配置如下所示:
    1.JVM堆内存分配3个G,年轻代分配2G(老年代1一G),年轻代比例8:1:1(Eden1.6G,S0:200M,S1:200M),方法区256M,栈1M
    -Xms3072M -Xmx3072M -Xmn2048M -Xss1M -XX:MetaspaceSize=256M -XX:MaxMetaspaceSize=256M -XX:SurvivorRatio=8

    2.配置CMS老年代垃圾收集器+ParNew年轻代垃圾收集器,回收年龄设置为5进入老年代,对过1M的大对象直接放入老年区
    -XX:MaxTenuringThreshold=5 -XX:PretenureSizeThreshold=1M -XX:+UseParNewGC -XX:+UseConcMarkSweepGC

    3.老年代使用超过92%执行fullgc,开启碎片压缩,在每次执行fullGC后都执行一次内存碎片压缩
    -XX:CMSInitiatingOccupancyFraction=92 -XX:+UseCMSCompactAtFullCollection -XX:CMSFullGCsBeforeCompaction=0

    nohup java -server -Xms3072M -Xmx3072M -Xmn2048M -Xss1M -XX:MetaspaceSize=256M -XX:MaxMetaspaceSize=256M -XX:SurvivorRatio=8 -XX:MaxTenuringThreshold=5 -XX:PretenureSizeThreshold=1M -XX:+UseParNewGC -XX:+UseConcMarkSweepGC -XX:CMSInitiatingOccupancyFraction=92 -XX:+UseCMSCompactAtFullCollection -XX:CMSFullGCsBeforeCompaction=0 -jar -Dspring.profiles.active=pro service-common-crm.jar &