• CMS垃圾收集器总结


    一 公司CMS参数

    先说一下公司CMS参数,年轻代3.5G, 其中survivor 50M。老年代1.5G,其实用不到500M,原空间250M。

    二 常见参数配置

      1 开启 CMS

      首先,要说的是,CMS只是老年代的垃圾收集器。其年轻代使用的是ParNew垃圾收集器。

      其次,JDK8默认的垃圾收集器并不是CMS,需要手动指定。-XX:+UseConcMarkSweepGC -XX:+UseParNewGC 

      2 设置堆大小

      使用CMS建议总堆空间不超过8G,最好是6G以内。因为如果发生FGC,太大的堆空间会让FGC的STW时间变的特别的长。

      -Xmx4G -Xms4G -Xmn1512M

      3 线程栈

      JDK8默认的线程栈大小是1M,绝大多数微服务项目可以调整为512K -XSS512K

      4 -XX:CMSInitiatingOccupancyFraction=70 -XX:+UseCMSInitiatingOccupancyOnly

       表示只有在老年代达到了70%才进行回收

      5 -XX:MetaspaceSize=314572800  其实是300M

         因为之前发生过元空间引发的FGC,所以我们项目把这个参数调大了。因为本项目的特点是,会请求大量的接口,引入大量的类。

      6 dump路径

       必须配置,因为如果发生了OOM,不dump的话,没法定位问题。

         -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=/data/applogs/system/error.dump

      7 GC 日志

       必须配置

          -XX:+PrintGC -XX:+PrintGCDateStamps -XX:+PrintGCDetails -XX:+PrintGCTimeStamps 

       -Xloggc:/data/log/gclog/gc.log

      8 压缩

      CMS是一种并发标记清除算法,而不是标记整理算法。所以,它不会进行碎片内存的移动和整理。

      -XX:+UseCMSCompactAtFullCollection -XX:CMSFullGCsBeforeCompaction=0

      0表示每次发生fullgc 都进行压缩整理

      9 卸载类

      -XX:+ExplicitGCInvokesConcurrentAndUnloadsClasses

      如果项目中使用了Netty,或者代码里用了堆外内存,只有FGC才能回收这样的堆外内存。也就是说想手动清理堆外内存就得执行System.gc()。而System.gc()触发的是serial old垃圾收集器,时间会很长,一般在5s左右。而FGC的STW的时间会很长,(CMS的完整FGC是退化为线性GC)。而CMS GC暂停服务的时间较短。因此,加了这个参数可以有效地回收堆外内存并且减少暂停时间。

      这两个参数也是用来改变System.gc()的默认行为用的;不同的 是这两个参数只能配合CMS使用(-XX:+UseConcMarkSweepGC),而且System.gc()还是会触发GC的,只不过不是触发一个 完全stop-the-world的full GC,而是一次并发GC周期。也还是会触发对外内存的回收。

      

    • CMS采用了Mark-Sweep算法,最后会产生许多内存碎片,当到一定数量时,CMS无法清理这些碎片了,CMS会让Serial Old垃圾处理器来清理这些垃圾碎片,而Serial Old垃圾处理器是单线程操作进行清理垃圾的,效率很低。所以使用CMS就会出现一种情况,硬件升级了,却越来越卡顿,其原因就是因为进行Serial Old GC时,效率过低。
    • 解决方案:使用Mark-Sweep-Compact算法,减少垃圾碎片
    • 调优参数(配套使用):-XX:+UseCMSCompactAtFullCollection 开启CMS的压缩
      -XX:CMSFullGCsBeforeCompaction 默认为0,指经过多少次CMS FullGC才进行压缩
    • 当JVM认为内存不够,再使用CMS进行并发清理内存可能会发生OOM的问题,而不得不进行Serial Old GC,Serial Old是单线程垃圾回收,效率低
    • 解决方案:降低触发CMS GC的阈值,让浮动垃圾不那么容易占满老年代
    • 调优参数:-XX:CMSInitiatingOccupancyFraction 92% 可以降低这个值,让老年代占用率达到该值就进行CMS GC

      

    附上公司启动脚本

      

    java -jar -javaagent:/data/gravity/gravity-agent.jar=appName=trade-om-app,baseUrl=http://gravity-api.amh-group.com,appType=jar 
    -Xms8192m -Xmx8192m -Xmn5460m -XX:MetaspaceSize=300m -XX:MaxMetaspaceSize=600m -XX:+UseConcMarkSweepGC -XX:MaxTenuringThreshold=15
    -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=/data/applogs/system/error.dump -XX:+ExplicitGCInvokesConcurrentAndUnloadsClasses
    -XX:CMSInitiatingOccupancyFraction=70 -XX:+PrintGCDateStamps -XX:+UseCMSInitiatingOccupancyOnly -XX:+UnlockDiagnosticVMOptions
    -XX:+UnsyncloadClass -XX:+UseParNewGC -XX:+PrintGCDetails -Xloggc:/data/applogs/system/gc_202007061528.log

      可以看到 配置eden和survivor比例没有配置,应该是使用默认的。

      

      IBM论文里说据他们统计95%的对象朝生夕死一样存活时间极短,为了保险默认实际使用了90%:设置eden 和survivor(两个)为4:1,每次GC都将Eden和其中一个survivor(from)中的存活对象复制到剩余的survivor(to)中

  • 相关阅读:
    微服务实战——微服务架构选型SpringCloud / Dubbo / K8S比较(一)
    微服务实战——Spring Cloud + Zuul Gateway + Eureka集成
    微服务实战——SpringCloud与Feign集成
    微服务实战——高可用的SpringCloudConfig
    制作自己的网站第二步***在Linux上装上需要的软件以及部署项目配置**
    Eclipse打war包方法以及Eclipse移植项目时JDK版本不匹配Project facet Java version 1.7 is not supported
    Eclipse移植项目时JDK版本不匹配Project facet Java version 1.7 is not supported
    个人网站开发***云服务器+Linux+域名***
    SaaS 系统架构,Spring Boot 动态数据源实现!
    Spring Security 是如何在 Servlet 应用中执行的?
  • 原文地址:https://www.cnblogs.com/juniorMa/p/15119143.html
Copyright © 2020-2023  润新知