记录一次线上机器JVM调优的历程

其实这件事已经发生很久了,因为最近想开始总结,所以想把这个过程记录下来,也算自己的总结。

在上半年四月份左右,经历了项目交接,我们在维护新项目的过程中,发现一个问题,有一个系统的线上机器在上线后一周左右,接口变得很慢,TP99等各种性能指标飙升。这是一个很典型的问题,应该很多同学也遇到过,最直接的解决办法就是将服务器重启,这个我们也试过,但是治标不治本。经过我们的观察发现系统上线一段时间以后就会进行频繁的Major GC。

当时项目是使用的jdk 1.7,JVM参数只是指定了堆的大小,没有GC日志输出。我们知道1.7当中默认的垃圾收集器是Parallel Scavenge,这是一个并行垃圾收集器,对年轻代和年老代都适用,而且关注系统的吞吐量,我们可以通过-XX:MaxGCPauseMillis和-XX:GCTimeRatio这两个参数来指定垃圾回收的时间,-XX:GCTimeRatio该参数的默认值为99,即垃圾回收时间只能占系统总运行时间的1%,而且这个时间还是年轻代和年老代回收的总时间。另外还有一个很关键的参数,也是导致这次问题发生的关键:-XX:ParallelGCThreads,这个参数是指定进行垃圾回收的线程数,如果不设置,JVM会根据服务器的情况去设置,若当前服务器核数小于8,则将这个值设置为CPU核数,若大于8,计算公式为:8+(CPU核数-8)*(5/8)。而因为现在的docker容器技术,每台服务器的CPU数量都很大,JVM不是取当前容器申请的核数,而是使用物理服务器的总核数,而我们那台服务器的核数是64,这样计算出来的ParallelGCThreads将达到43个。也就是在进行GC的时候将同时有43个线程共同完成,我们知道在Parallel 中GC时间是固定的,而43个GC线程进行线程间的切换就要花费多少时间,真正用在GC上的时间少的可怜。这也就导致了虽然一直在进行Major GC,但是垃圾却始终回收不掉的情况,导致线上机器的内存使用率一直下不来。

思考一下,指定GC回收时间之后,随着访问量的不断增加,时间和GC线程数一定的情况下,JVM所能回收的垃圾是一定的,这样就必定导致垃圾的堆积,到最终就是频繁的Major GC,甚至是Full GC。那为什么jdk1.7以及jdk1.8的默认收集器都是Parallel呢,我觉得对于业务频繁更新的系统,只要设置好参数,使用Parallel是没有问题的,因为频繁的业务更新,必然会频繁上线使得机器重启,这样就可以避免垃圾的堆积,毕竟垃圾的堆积也是需要时间的,例如我们当时的系统是上线一周之后才出现,而且还是参数设置的极不合理的情况下,Parallel还是能用的,当然最终我们没有再使用Parallel,而是使用了ParNew结合CMS的组合,因为我们更关注的是低停顿而不是高吞吐。

我们的服务器一般都是常规的4C8G的机器,给JVM分配了6G的内存,其中年轻代分配了2G,Eden和Survivor默认比例8:1:1,这样换算下来Eden区1.6G,一个Survivor区为0.2G,这样设置的目的也是尽可能让更多的对象在年轻代就被回收。每次进行Minor GC需要回收的空间可能就有1.8G,为了加快回收速度,我们配置了ParallelGCThreads=4,这样年轻代的回收速度也得到了提升,目前线上Minor GC的停顿平均时间稳定在30ms,如下图所示。

年老代空间大概为4G左右,通过 -XX:CMSInitiatingOccupancyFraction=75以及 -XX:ConcGCThreads=2参数设置触发CMS回收的时机和回收时的线程数,这样的参数设置使得线上机器基本没有发生Major GC和Full GC。

以上提到的部分参数只是针对内存比较小的服务器,对于大内存的服务器,比如32G内存的服务器,可能新生代就会分配10G以上,这种情况下仍然 使用ParNew和CMS的组合效果就很差了,这个时候就需要使用G1,G1设计的初衷就是为用户提供大内存、低GC停顿时间的应用解决方案,它将整个内存区域分成大小相等的若干块,每个块会指定是新生代还是老年代或者大对象区,通过复制算法来进行垃圾回收。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值