微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

2020-11-25

JDK7-8认的垃圾收集器: CMS,  2核4G的设备 CMS(Concurrent Mark Sweep):标记清除算法 开始关注较少的停顿时间- 买一送一 : 适用于老年代,青年代使用的是ParaNew收集器
  • 意义:减少垃圾收集停顿时间,真正实现了垃圾收集和任务线程并行工作;
  • 目标:以最小的停顿时间为目标;
  • 缺点:
    • 卡顿:由于和工作线程一起工作,对cpu敏感;cpu核数少于4个cpu不足的时候,出现cpu竞争,影响系统的吞吐量;
    • 无法处理浮动的垃圾
    • 产生2次stw;
    • 标记清除算法,会出现一些内存碎片;
  • 分配担保机制:会产生promotion fail进而导致concurrent mode failure失败产生full gc;
    • cms认使用超过68%的内存的时候就会触发full gc,回退到serial-old GC;
  • 解决办法:
    • 碎片整理,设置几次cms后就进行一次碎片整理;防止空间够但大对象连续空间不够;
    • 提前触发cms,预留足够的内存空间;适当的调小68%的比例值;
  • 参数设置
    • -XX:CMSInitiatingOccupancyFraction:认68%,给应用程序留下足够的空间,避免fullgc;
    • -XX:UseCMSCompactAtFullCollection:进行碎片整理;但是会增加停顿的时长;
    • -XX:CMSFullGCsBeforeCompaction:碎片整理的频率;
  • 过程
    • 初始标记:stw ,标记根gc-root对象
      • jvm虚拟机栈对象;
      • 本地方法栈的引用;
      • static变量引用;
      • 常量池的引用
    • 并发标记-最耗时间:根据gc-root搜索,判断可达性;
    • 重新标记:stw,标记检验标记并发期间产生变化的对象和新对象,更新逃逸对象;
    • 并发清除:清楚不可达的对象,为下次gc做准备;
  • 适用场景
    • 多核cpu,追求低停顿时间;
    • 老年代不频繁的gc
 

项目实战CMS参数设置:
JVM_ARGS="-server -Dapp.key=zcm-pos-coupon-web -Dfile.encoding=UTF-8 -Dsun.jnu.encoding=UTF-8 -Djava.io.tmpdir=/tmp --Duser.timezone=GMT+08 -XX:-LoopUnswitching -XX:-OmitStackTraceInFastThrow"
JVM_GC="-XX:+PrintGC -XX:+PrintGCDetails -XX:+PrintHeapAtGC -XX:+PrintTenuringdistribution -XX:+PrintGCTimeStamps -XX:+PrintGCDateStamps"
JVM_GC=$JVM_GC" -XX:+UseConcmarkSweepGC -XX:CMSFullGCsBeforeCompaction=0 -XX:+UseCMSCompactAtFullCollection -XX:+ExplicitGCInvokesConcurrent -XX:CMSInitiatingOccupancyFraction=70 -XX:+UseCMSInitiatingOccupancyOnly"
JVM_HEAP="-Xmn1g -Xss512k -XX:SurvivorRatio=6 -XX:PermSize=256M -XX:MaxPermSize=256M -XX:ReservedCodeCacheSize=64m -XX:InitialCodeCacheSize=64m -XX:+HeapDumpOnOutOfMemoryError"
JVM_SIZE="-Xmx4g -xms4g"

csm参数解析说明:

-XX:+UseConcmarkSweepGC 此参数将启动 CMS 回收器。认新生代是 ParNew + CMS,也可以设置 Serial 为新生代收集器。该参数等价于 -Xconcgc。 -XX:ParallelGCThreads 指定线程数。认并发线程数是:(ParallelGCThreads + 3)/ 4)。 -XX:CMSInitiatingOccupancyFraction 由于 CMS 回收器不是独占式的,在垃圾回收的时候应用程序仍在工作,所以需要留出足够的内存给应用程序,否则会触发 FGC。而什么时候运行 CMS GC 呢?通过该参数即可设置,该参数表示的是老年代的内存使用百分比。当达到这个阈值就会执行 CMS。 认是68。 如果老年代内存增长很快,建议降低阈值,避免 FGC,如果增长慢,则可以加大阈值,减少 CMS GC 次数。提高吞吐量。 -XX:+ UseCMSCompactAtFullCollection 由于 CMS 使用标记清理算法,内存碎片无法避免。该参数指定每次 CMS 后进行一次碎片整理。 -XX:CMSFullGCsBeforeCompaction 由于每次进行碎片整理将会影响性能,你可以使用该参数设定多少次 CMS 后才进行一次碎片整理,也就是内存压缩。 -XX:CMSInitiatingPermOccupancyFraction 当永久区占用率达到这一百分比时,启动 CMS 回收(前提是 -XX:+CMSClassUnloadingEnabled 激活了)。 -XX:UseCMSInitiatingOccupancyOnly 表示只在到达阈值的时候才进行 CMS 回收。 XX:CMSWaitDuration=2000 由于CMS GC 条件比较简单,JVM有一个线程定时扫描Old区,时间间隔可以通过该参数指定(毫秒单位),认是2s。 CMS 的 GC 日志 就是 CMS。    
配置参数 功能
-xms 初始堆大小。如:-xms4g
-Xmx 最大堆大小。如:-Xmx4g
-Xmn 新生代大小。通常为 Xmx 的 1/3 或 1/4。新生代 = Eden + 2 个 Survivor 空间。 实际可用空间为 = Eden + 1 个 Survivor,即 90%
-Xss JDK1.5+ 每个线程堆栈大小为 1M,一般来说如果栈不是很深的话, 1M 是绝对够用了的。
-XX:NewRatio 新生代与老年代的比例,如 –XX:NewRatio=2,则新生代占整个堆空间的1/3,老年代占2/3
-XX:SurvivorRatio 新生代中 Eden 与 Survivor 的比值。认值为 8。即 Eden 占新生代空间的 8/10,另外两个 Survivor 各占 1/10
-XX:PermSize 永久代(方法区)的初始大小
-XX:MaxPermSize 永久代(方法区)的最大值 
  cms promotion Failed & concurrent mode failure 两种失败? 通过 +PrintGCDtail  打印 gc 的详细日志;   promotion Failed 问题分析: 该问题是在进行 MinorGC 时, Survivor Space 放不下,对象只能放入老年代,而此时老年代有碎片或者正在进行 CMS 垃圾回收,没有足够的空间也放不下。 promotion Failed 时老年代 CMS 还没有机会进行回收,又放不下转移到老年代的对象,因此会出现下一个问题 concurrent mode filure ,需要 stop-the-wold 降级为 GC-Serial Old 。此时 JVM 将采用 stop-the-world 及后备的串型收集器来进行垃圾回收,此时的 CMS 已经没有什么意义: 解决办法:
  • -XX:UseCMSCompactAtFullCollection -XX:CMSFullGCBeforeCompaction=5 设置 5 次 gc 后进行一次整理碎片操作;
  • 调大新生代或者 survivor 的空间;
  产生 concurrent mode failure 原因总结:
  • 1 、老年代所剩下的空间小于 Eden 区域 + from 区域的空间,
  • 2 、在 CMS 执行老年代的回收时有业务线程试图将大的对象放入老年代,导致 CMS 在老年代的回收慢于业务对象对老年代内存的分配;
问题分析: 调低触发 CMS GC 执行的阈值, CMS GC 触发主要由 CMSInitia@R_52_5020@ccupancyFraction 值决定,认情况下是当旧生代已用空间为 68% 时,即触发 CMS GC , 在出现 concurrent mode failure 的情况下,可考虑调小这个值,提前 CMS GC 的触发,以保证旧生代有足够的空间。 解决办法:
  • 调小 CMSInitia@R_52_5020@ccupancyFraction 这个值,提前触发 GC ;
  • 调大老年代的空间;
  总结一句话: 使用标记整理 清除碎片提早进行 CMS 操作

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 [email protected] 举报,一经查实,本站将立刻删除。

相关推荐