记一次GC优化

现象

young gc时间达到了150-500ms之间,每个服务器的时间不一样,都在这个区间,监控的tp99和tp999有明显的毛刺

环境

docker环境,服务器规格:2c4g,容器:tomcat8,jdk:8,回收器:cms

排查过程

1、首先想到查看gc日志,发现有如下日志:

[GC (Allocation Failure) [ParNew: 561827K->2873K(629120K), 0.4622482 secs] 1149586K->590676K(2027264K), 0.4626134 secs] [Times: user=0.92 sys=0.00, real=0.46 secs]

可以看到长达400多ms

2、然后想,难道是新生代内存太多了,通过jmap head命令把当前堆的信息输出到文件,查看:

可以看到新生代并不大,根据前面的GC日志,也就回收了500多M的对象,不可能这么慢

3、然后想,难道docker负载比较大,查看docker服务器信息,cpu、内存、网络、磁盘都正常

4、既然docker本身很正常,哪就奇怪了,是什么导致young gc比较慢呢?做什么事,耗费了时间呢?但又感觉无从下手

5、后与架构师聊了下这个情况,提到gc的线程数,我说是默认的,默认的情况下,gc会开启服务器的cpu的核数的个数的线程数,这里要最关键的是取的是物理机的核数,而不是docker的核数,我查了下这个docker宿主机的核数是60,意味着什么,我想大家都知道了,开启了太多的线程,开启线程也需要时间,线程之间的竞争也多起来,时间自然消耗就大了

解决

指定gc线程数和编译线程数

-XX:ParallelGCThreads=2 -XX:CICompilerCount=2

观察一段时间,发现young gc时间下降到了20-60ms之间的水平,提高了6,7倍吧,再看监控的tp99和tp999瞬间丝滑了很多

额外收获

发现之前,容器重启cpu彪高的问题也没消失了,原来是它的锅

总结

容器最佳配置

1、堆内存配置

1C2G容器:-Xms512m -Xmx512m,负载较高的可设置为-Xms800m -Xmx800m

2C4G容器:-Xms2048m -Xmx2048m

4C8G容器:-Xms4096m -Xmx4096m

2、GC及编译线程配置

-XX:ParallelGCThreads=[cpu核数]

注意:如果ParallelGCThreads 没有配置,默认会使用物理机的cpu核数设置回收线程数,这会严重降低GC性能且产生过多GC线程,因此所有容器都应配置该参数;

-XX:CICompilerCount=[cpu核数 >2 ? cpu核数 : 2]

可以优化类文件编译性能,默认会使用物理机cpu核数进行设置,所有容器都应该手动配置;

3、元空间

-XX:MetaspaceSize 元空间;
-XX:MaxMetaspaceSize 最大元空间;
元空间对应以前的永久代内存,推荐设置为256~512M;
注意:MaxPermSize参数在JDK8中已经废弃,应使用MetaspaceSize 进行设置

4、回收器类型

-XX:+UseParallelGC 并行回收器(默认)
-XX:+UseConcMarkSweepGC CMS回收器
-XX:+UseG1GC G1回收器
Jdk1.8的容器推荐使用G1,旧版本jdk容器推荐使用CMS,这两个回收器都是响应时间优先的算法,对响应时间敏感的应用推荐使用;

GC日志

当GC有问题时,可以打印GC日志帮助排查,相关参数有:
-Xloggc:/export/Logs/jvm/gc.log
-XX:GCLogFileSize=100M
-XX:+PrintGCDetails
-XX:+PrintGCDateStamps
-XX:+ PrintGCCause
-XX:+PrintClassHistogramBeforeFullGC
-XX:+PrintClassHistogramAfterFullGC
-XX:+HeapDumpBeforeFullGC
-XX:+HeapDumpAfterFullGC

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值