Su的技术博客

  • 首页
  • Java
  • MySQL
  • DDD
  • 事故复盘
  • 架构方案
  • AI
  • Other
  • 工具
  • 打赏
  • 关于
路很长,又很短
  1. 首页
  2. Java
  3. 正文
                           

【JVM】生产环境的CMS垃圾回收,一定要这样配置参数

2023-09-18 39点热度 0人点赞 0条评论

此篇文章只聚焦于如何配置一个比较合理的采用CMS作为垃圾回收器的JVM参数。首先要说的是,JDK8要使用CMS,那么必须显示申明,因为它采用的默认垃圾回收器是ParallelGC。如何验证它默认采用的垃圾回收器呢?非常简单,运行如下代码:

package com.afei.test.main;

import java.util.ArrayList;
import java.util.List;

/**
* @author 公众号: 阿飞的博客
*/
public class Main{

private static final int _1M = 1024*1024;

public static void main(String[] args){

List<byte[]> byteList = new ArrayList<>();
for(int i=0; i<Integer.MAX_VALUE; i++){
byte[] test = new byte[_1M];
byteList.add(test);
}
}

}

 

然后配置JVM参数:

-verbose:gc -XX:+PrintGCDetails

运行几秒钟后,我们强行停止JVM进程,就会在控制台中看到如下日志从而佐证JDK8采用的默认垃圾回收器就是ParallelGC:

[Full GC (Allocation Failure) [PSYoungGen: 342021K->342021K(348672K)] [ParOldGen: 1397423K->1397406K(1398272K)] 1739445K->1739427K(1746944K), [Metaspace: 3357K->3357K(1056768K)], 0.1902415 secs] [Times: user=0.26 sys=0.01, real=0.19 secs] 

或者可以通过如下信息得知默认垃圾回收器为ParallelGC:生产环境的CMS垃圾回收,一定要这样配置参数

CMS用法

接下来笔者从多个方面介绍如何配置一个较好的使用CMS垃圾回收器的JVM参数参数。

显示申明CMS

显示申明垃圾回收器为CMS+parNew非常简单,只需要添加如下两个JVM参数:

-XX:+UseConcMarkSweepGC -XX:+UseParNewGC

这时候,再运行上面的代码,就会得到如下信息。由下图可知,这时候年轻代采用的是ParNew,而老年代采用的是CMS(concurrent mark-sweep):生产环境的CMS垃圾回收,一定要这样配置参数

显示申明CMS只是使用CMS的第一步,接下来还有很多优化需要我们去做,还有很多JVM参数等待我们去配置。

堆大小

接下来,最重要的就是申明年轻代和老年代的大小。由于采用的CMS+ParNew。建议堆大小不要超过8G,最好6G以内,因为CMS+ParNew组合情况下发生的FGC是采用MSC算法且单线程回收,如果堆内存很大,FGC时STW时间会非常恐怖。笔者这里以4G举例,这时候再添加几个JVM参数,我们得到如下的配置。这里笔者设置的年轻代大概是1.5G,老年代大概是2.5G。这算是一个比较合理的比例搭配。如果你的JVM参数这样搭配但是GC情况仍然不是很好,那么可能需要根据你的业务特性进行特别的调优:

-Xmx4g -Xms4g -Xmn1512m

线程栈

JDK8默认的线程栈大小为1M,有点偏大。以笔者的经验,绝大部分微服务项目是可以调整为512k,甚至256k的(笔者的项目就是256k,运行的棒棒哒):

-Xss256k

Old回收阈值

既然配置的是CMS,那么如下两个参数一定要加上。为什么要加上这两个JVM参数呢?这是因为CMS回收条件非常复杂,如果不通过CMSInitiatingOccupancyFraction和UseCMSInitiatingOccupancyOnly限制只在老年代达到75%才回收的话(这个阈值可以根据具体情况适当调整),当线上碰到一些CMS GC时,是很难搞清楚原因的:

-XX:CMSInitiatingOccupancyFraction=75 -XX:+UseCMSInitiatingOccupancyOnly 

CMS GC触发条件相关文章推荐--【JVM 源码解读之 CMS GC 触发条件】:https://mp.weixin.qq.com/s/Mu-Xz4CLgdxJhcMJ7aKAHg

元数据空间

如果是微服务架构,那么对于绝大部分应用来说,128M的元数据完全够用。不过,JDK8的元数据空间并不是指定多少就初始化多大的空间。而是按需扩展元数据空间。所以,我们可以设置256M。如果不设置这两个参数的话,元数据空间默认初始化只有20M出头,那么就会在应用启动过程中,Metaspace扩容发生FGC:

-XX:MaxMetaspaceSize=256m -XX:MetaspaceSize=256M

dump路径

设定如下两个参数(需要说明的是,HeapDumpPath参数指定的路径需要提前创建好,JVM没办法在生成dump文件时创建该目录),当JVM内存导致导致JVM进程退出时能自动在该目录下生成dump文件:

-XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=/data/log/jvmdump/

GC日志

这个必须有,不然线上环境GC问题都不好排查。并且loggc所在目录(/data/log/gclog/)和dump路径一样,必须提前创建好,JVM无法自动创建该目录:

-XX:+PrintGCDetails -XX:+PrintGCDateStamps -Xloggc:/data/log/gclog/gc.log

压缩

我们都知道,CMS GC是并发的垃圾回收器,它采用的是标记清除算法,而不是压缩算法。意味着随着时间的推移,碎片会越来越多,JVM终究会触发内存整理这个动作。那么,什么时候整理内存碎片呢?跟下面两个参数有很大的关系。第一个参数是开启这个能力,第二个参数表示在压缩(compaction)内存之前需要发生多少次不压缩内存的FGC。CMS GC不是FGC,在CMS GC搞不定的时候(比如:concurrent mode failure),会触发完全STW但不压缩内存的FGC(假定命名为NoCompactFGC),或者触发完全STW并且压缩内存的FGC(假定命名为CompactFGC)。所以,这个参数的意思就是,连续多少次NoCompactFGC后触发CompactFGC。如果中间出现了CMS GC,那么又需要重新计数NoCompactFGC发生的次数:

-XX:+UseCMSCompactAtFullCollection -XX:CMSFullGCsBeforeCompaction=0

CMS回收条件推荐文章--[JVM 源码解读之 CMS 何时会进行 Full GC]:https://mp.weixin.qq.com/s/zn3-9e7ZZ7skLo1XDL0xww

笔者这里给出的配置事实上是默认值,即每次CMS GC搞不定的情况下触发CompactFGC。这两个参数很不好理解,为此,笔者举几个例子,假定有3种GC方式:CMS GC,NoCompactFGC, CompactFGC(如下时yi du a):

if(should_compact){
    // mark-sweep-compact
    do_compaction_work(clear_all_soft_refs) 
} else {   
    // mark-sweep
    do_mark_sweep_work(clear_all_soft_refs,first_state,should_start_over);
}

NoCompactFGC就是不压缩内存的FGC,采用的是标记清除(Mark-Sweep)算法,CompactFGC是会压缩内存的FGC,采用的是标记清除压缩算法(Mark Sweep Compact),然后假设我们配置了-XX:CMSFullGCsBeforeCompaction=3,那么:

1、CMS GC, NoCompactFGC, NoCompactFGC, NoCompactFGC, CompactFGC(这时候如果发生FGC就会压缩内存)
2、CMS GC, NoCompactFGC, NoCompactFGC, CMS GC, NoCompactFGC(这时候如果发生FGC不会压缩内存,因为在此之前并没有连续3次NoCompactFGC)
3、CMS GC, CMS GC, CMS GC, NoCompactFGC(如果前面连续发生的是CMS GC,那么接下来触发的FGC还不会压缩内存)

one more

最后,再推荐给大家一个搭配CMS时很好用的JVM参数,如下所示。官方对该参数的说明为:A System.gc() request invokes a concurrent collection and also unloads classes during such a concurrent gc cycle (effective only when UseConcMarkSweepGC)。这句话总结如下:1、只有在使用CMS时才有效。2、当调用System.gc()时会用CMS这个并行垃圾回收器去进行回收(比如大量使用DirectByteBuffer进行堆外内存操作,需要FGC来回收堆外内存的场景。就可以通过该参数让本来需要FGC才能搞定的事情用CMS GC就可以搞定了)。3、除了能唤起并行垃圾回收器,还能卸载类。

-XX:+ExplicitGCInvokesConcurrentAndUnloadsClasses

最终,得到我们配置的完整的JVM参数配置如下(此参数在以前笔者负责的一个微服务项目中运行了数年,单机并发1000+,CMS GC大概是8天左右一次):

-Xms4g -Xmx4g -Xmn1512m -server -Xss256k -XX:MetaspaceSize=256M  -XX:MaxMetaspaceSize=256m -XX:+PrintGCDetails -XX:+PrintGCDateStamps -Xloggc:/data/log/gclog/gc.log -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=/data/log/jvmdump/ -XX:+UseConcMarkSweepGC -XX:+UseParNewGC  -XX:CMSInitiatingOccupancyFraction=75 -XX:+UseCMSInitiatingOccupancyOnly -XX:+UseCMSCompactAtFullCollection -XX:CMSFullGCsBeforeCompaction=0 -XX:+CMSClassUnloadingEnabled -XX:+TieredCompilation  -XX:+ExplicitGCInvokesConcurrentAndUnloadsClasses

最后,笔者再介绍一个很好的校验JVM参数的网址:https://opts.console.heapdump.cn/,这里我们可以用到它的“参数检查”。不过需要说明的是:尽信书不如不读书,此网址的校验结果只是作为参考,是否完全符合你的生产环境,还得视情况而定,毕竟JVM调优可不是一件简单的事情:生产环境的CMS垃圾回收,一定要这样配置参数

本文仅供学习!所有权归属原作者。侵删!文章来源: 占小狼的博客 -阿飞 :http://mp.weixin.qq.com/s/vrIvphlkwnQnDhv9JdhO8g

更多文章:

  1. 系统设计入门:成为高级软件工程师的指南
  2. Spring事务无法生效的11个场景
  3. Routing Elasticsearch架构VI:路由
  4. 记一次升级MySQL驱动包引发的事故
  5. DDD系列第五讲:聊聊如何避免写流水账代码
  6. Spring中@Autowired和@Inject注解的区别?
  7. 殷浩详解DDD系列 第二讲 - 应用架构
  8. Chrome插件(扩展)开发全攻略2.6w字,看这篇就够了!
标签: JVM GC CMS 垃圾回收 Java 性能调优
最后更新:2023-09-18

coder

分享干货文章,学习先进经验。

打赏 点赞
< 上一篇
下一篇 >

文章评论

razz evil exclaim smile redface biggrin eek confused idea lol mad twisted rolleyes wink cool arrow neutral cry mrgreen drooling persevering
取消回复

文章目录
  • CMS用法
    • 显示申明CMS
    • 堆大小
    • 线程栈
    • Old回收阈值
    • 元数据空间
    • dump路径
    • GC日志
    • 压缩
    • one more
最新 热点 推荐
最新 热点 推荐
单体分层应用架构剖析 MySQL事务死锁问题排查 浅谈DDD中的聚合 高并发场景下JVM调优实践之路 ChatGPT的探索与实践 生产环境的CMS垃圾回收,一定要这样配置参数
Log4j框架疯狂写日志,导致磁盘打满问题排查高并发场景下JVM调优实践之路3.编程语言的演化(译)4.架构风格 vs. 架构模式 vs. 设计模式(译)5.单体架构(译)6.分层架构(译)
2021.07.13 我们是这样崩的 QQ音乐高可用架构体系 Eureka源码剖析之五:服务下线 Arthas实战-线上热更新代码只需3步 【视频】NettyInAction作者:统治一切的框架Netty- One Framework to rule them all 设计模式在外卖营销业务中的实践

AIGC (1) BASE (1) bigkey (1) CAP (1) codeium (2) Copilot (2) hotkey (1) inject (1) jar包 (1) mvc (1) OOP (1) UML (1) vivo (2) 事务隔离级别 (1) 人工智能 (2) 代码质量 (1) 低耦合 (1) 依赖倒置原则 (1) 六边形架构 (1) 分层架构 (3) 分布式事务 (1) 分页 (1) 单体架构 (2) 可复用性 (1) 可读性 (1) 合同 (1) 后端开发 (1) 命名 (1) 四色建模法 (1) 垃圾回收器 (1) 开源 (1) 性能调优 (4) 智能助手 (1) 架构模式 (1) 架构设计 (4) 架构风格 (1) 模块 (1) 死锁 (1) 物流 (1) 系统架构 (4) 缓存穿透 (1) 缓存雪崩 (1) 编程助手 (3) 编程技能 (1) 编程语言 (2) 聚合 (1) 软件工程师 (1) 软件架构 (2) 驱动升级 (1) 高内聚 (1)

COPYRIGHT © 2014-2023 verysu.com . ALL RIGHTS RESERVED.

Theme Kratos Made By Seaton Jiang

粤ICP备15033072号-2