美文网首页一些收藏
系统压测FullGC日志分析

系统压测FullGC日志分析

作者: 千淘萬漉 | 来源:发表于2020-06-22 20:18 被阅读0次

应用背景分析

压测一个业务系统,其中JVM堆内存参数如下,堆内存设置了6g,新生代3g,老年代相应的为3g,采用了CMS垃圾回收器,新生代则默认为ParNew回收器,设定触发FullGC规则为老年代使用率达到70%(默认值为75%),调低该值的目的在于降低内存碎片的影响,希望更早的触发垃圾回收。CMS垃圾回收时会采用标记清除算法,同时默认会在清除以后执行整理压缩,避免浮动垃圾与内存碎片。

 -Xms6144M -Xmx6144M -Xmn3072M -XX:+DisableExplicitGC -XX:+UseConcMarkSweepGC -XX:+CMSParallelRemarkEnabled -XX:LargePageSizeInBytes=128m -XX:+UseFastAccessorMethods -XX:+UseCMSInitiatingOccupancyOnly -XX:CMSInitiatingOccupancyFraction=70 -XX:+PrintGCDetails -XX:+PrintGCDateStamps -verbose:gc -Xloggc:/wls/springboot/logs/gc.log -Djava.net.preferIPv4Stack=true

设定了如上的JVM参数下开始进行压测,现在分析一波基于CMS的FullGC日志。

Phase 1: Initial Mark 初始标记


该阶段会STW现象,这是CMS中两次stop-the-world事件中的一次。它有两个目标:一是标记老年代中所有的GC Roots;二是标记被年轻代中活着的对象引用的对象。

2020-04-28T16:09:39.160+0800: 1108.793: [GC (CMS Initial Mark) [1 CMS-initial-mark: 2204173K(3145728K)] 2370012K(5976896K), 0.0514097 secs] [Times
: user=0.13 sys=0.04, real=0.05 secs] 

从以上日志信息中可以提取到如下信息:

  • 老年代容量3g,当前使用2.1g
  • 整个堆容量5.7g,当前使用2.26g
  • 耗时0.0514097s

Phase 2: Concurrent Mark 并发标记


这个阶段不会STW,JVM会遍历整个老年代并且标记所有存活的对象,从“初始化标记”阶段找到的GC Roots开始。并发标记的特点是和应用程序线程同时运行,并不是老年代的所有存活对象都会被标记,因为标记的同时应用程序会改变一些对象的引用等。截取GC日志如下:

2020-04-28T16:09:39.213+0800: 1108.845: [CMS-concurrent-mark-start]
2020-04-28T16:09:39.490+0800: 1109.123: [CMS-concurrent-mark: 0.278/0.278 secs] [Times: user=1.09 sys=0.46, real=0.28 secs] 

其中,0.278/0.278 secs就是展示该阶段持续的时间和时钟时间;

Phase 3: Final Remark 重新标记


此处可以细分三个小阶段,只有第三个Final Remark阶段会有STW。

1、Concurrent Preclean

这里仍是一个回收线程并发执行阶段,和应用线程并行运行。前一个阶段在并行运行的时候,一些对象的引用已经发生了变化,当这些引用发生变化的时候,JVM会标记堆的这个区域为Dirty Card(包含被标记但是改变了的对象,被认为"dirty"),这就是 Card Marking。

2020-04-28T16:09:39.491+0800: 1109.124: [CMS-concurrent-preclean-start]
2020-04-28T16:09:39.558+0800: 1109.191: [CMS-concurrent-preclean: 0.067/0.067 secs] [Times: user=0.15 sys=0.07, real=0.07 secs] 

2、Concurrent Abortable Preclean

又一个并发阶段不会停止应用程序线程。这个阶段尝试着去承担STW的Final Remark阶段足够多的工作。这个阶段持续的时间依赖好多的因素,由于这个阶段是重复的做相同的事情直到发生aboart的条件(比如:重复的次数、多少量的工作、持续的时间等等)之一才会停止。

2020-04-28T16:09:39.559+0800: 1109.192: [CMS-concurrent-abortable-preclean-start]
2020-04-28T16:09:40.812+0800: 1110.445: [GC (Allocation Failure) 2020-04-28T16:09:40.813+0800: 1110.445: [ParNew: 2567678K->51415K(2831168K), 0.15
12751 secs] 4771852K->2259993K(5976896K), 0.1521682 secs] [Times: user=0.85 sys=0.03, real=0.16 secs] 
2020-04-28T16:09:41.753+0800: 1111.386: [CMS-concurrent-abortable-preclean: 2.030/2.194 secs] [Times: user=7.99 sys=2.63, real=2.20 secs] 

这个阶段很大程度的影响着即将来临的Final Remark的停顿

3、Final Remark

清理前做最终的标记,这个阶段是CMS中第二个并且是最后一个STW的阶段。该阶段的任务是完成标记整个年老代的所有的存活对象。由于之前的预处理是并发的,它可能跟不上应用程序改变的速度,这个时候,STW是非常需要的来完成这个严酷考验的阶段。通常CMS尽量运行Final Remark阶段在年轻代是足够干净的时候,目的是消除紧接着的连续的几个STW阶段。

2020-04-28T16:09:41.757+0800: 1111.390: [GC (CMS Final Remark) [YG occupancy: 1451165 K (2831168 K)]
2020-04-28T16:09:41.757+0800: 1111.390: [Rescan (parallel) , 0.2057074 secs]
2020-04-28T16:09:41.963+0800: 1111.595: [weak refs processing, 0.0000816 secs]
2020-04-28T16:09:41.963+0800: 1111.596: [class unloading, 0.1070335 secs]
2020-04-28T16:09:42.070+0800: 1111.703: [scrub symbol table, 0.0133941 secs]
2020-04-28T16:09:42.083+0800: 1111.716: [scrub string table, 0.0012260 secs][1 CMS-remark: 2208578K(3145728K)] 3659743K(5976896K), 0.3312628 secs] [Times: user=1.28 sys=0.01, real=0
.33 secs]
  • CMS Final Remark – 收集阶段,这个阶段会标记老年代全部的存活对象,包括那些在并发标记阶段更改的或者新创建的引用对象;YG occupancy: 1451165 K (2831168 K) – 年轻代当前占用情况(1.38g)和容量(2.7g);
  • [Rescan (parallel) , 0.0085125 secs] – 这个阶段在应用停止的阶段完成存活对象的标记工作;
  • weak refs processing,处理弱引用
  • class unloading 卸载类
  • scrub symbol table 清理符号对象
  • scrub string table 清理字符串常量对象

通过以上5个阶段的标记,老年代所有存活的对象已经被标记并且现在要通过Garbage Collector采用清扫的方式回收那些不能用的对象了。

Phase 4: 垃圾回收


这个阶段可以划分两个小阶段,这两个都不会STW。

1、Concurrent Sweep

这个阶段的目的就是移除那些不用的对象,回收他们占用的空间并且为将来使用。

2020-04-28T16:09:43.698+0800: 1113.331: [CMS-concurrent-sweep: 1.579/1.609 secs] [Times: user=5.35 sys=2.34, real=1.61 secs] 

2、Concurrent Reset

这个阶段并发执行,重新设置CMS算法内部的数据结构,准备下一个CMS生命周期的使用。

2020-04-28T16:09:43.699+0800: 1113.332: [CMS-concurrent-reset-start]
2020-04-28T16:09:43.707+0800: 1113.339: [CMS-concurrent-reset: 0.008/0.008 secs] [Times: user=0.03 sys=0.00, real=0.01 secs]

0.008/0.008 secs为该阶段的持续时间。

总结


总体来看,FGC的时长大约在4s,其中STW的时长为0.27+0.20+0.1+0.33=0.81s。FGC的回收时长较大,原因在于JVM堆内存的空间较大,导致在多个标记阶段耗时较长,且FGC期间因为会开启多线程进行并发回收,会出现CPU使用率上的毛刺现象,但是整体来看STW上的0.81s满足CMS一贯的低延时优点,如果在生产上内存*2的情况下,FGC和STW时长可能会线性倍增两倍。如果观察线上FGC时长过大,CPU使用率因FGC出现较多毛刺的情况下,说明CMS在应对大内存服务的回收时会显得力不从心,可以考虑采用G1回收器对JVM进行调优处理。

以下展示为CMS的完整GC日志与时间,可供大家学习参考。

2020-04-28T16:09:39.160+0800: 1108.793: [GC (CMS Initial Mark) [1 CMS-initial-mark: 2204173K(3145728K)] 2370012K(5976896K), 0.0514097 secs] [Times
: user=0.13 sys=0.04, real=0.05 secs] 

2020-04-28T16:09:39.213+0800: 1108.845: [CMS-concurrent-mark-start]
2020-04-28T16:09:39.490+0800: 1109.123: [CMS-concurrent-mark: 0.278/0.278 secs] [Times: user=1.09 sys=0.46, real=0.28 secs] 

2020-04-28T16:09:39.491+0800: 1109.124: [CMS-concurrent-preclean-start]
2020-04-28T16:09:39.558+0800: 1109.191: [CMS-concurrent-preclean: 0.067/0.067 secs] [Times: user=0.15 sys=0.07, real=0.07 secs] 

2020-04-28T16:09:39.559+0800: 1109.192: [CMS-concurrent-abortable-preclean-start]
2020-04-28T16:09:40.812+0800: 1110.445: [GC (Allocation Failure) 2020-04-28T16:09:40.813+0800: 1110.445: [ParNew: 2567678K->51415K(2831168K), 0.15
12751 secs] 4771852K->2259993K(5976896K), 0.1521682 secs] [Times: user=0.85 sys=0.03, real=0.16 secs] 
2020-04-28T16:09:41.753+0800: 1111.386: [CMS-concurrent-abortable-preclean: 2.030/2.194 secs] [Times: user=7.99 sys=2.63, real=2.20 secs] 

2020-04-28T16:09:41.757+0800: 1111.390: [GC (CMS Final Remark) [YG occupancy: 1451165 K (2831168 K)]2020-04-28T16:09:41.757+0800: 1111.390: [Resca
n (parallel) , 0.2057074 secs]2020-04-28T16:09:41.963+0800: 1111.595: [weak refs processing, 0.0000816 secs]2020-04-28T16:09:41.963+0800: 1111.596
: [class unloading, 0.1070335 secs]2020-04-28T16:09:42.070+0800: 1111.703: [scrub symbol table, 0.0133941 secs]2020-04-28T16:09:42.083+0800: 1111.
716: [scrub string table, 0.0012260 secs][1 CMS-remark: 2208578K(3145728K)] 3659743K(5976896K), 0.3312628 secs] [Times: user=1.28 sys=0.01, real=0
.33 secs] 
2020-04-28T16:09:42.089+0800: 1111.722: [CMS-concurrent-sweep-start]
2020-04-28T16:09:42.778+0800: 1112.411: [GC (Allocation Failure) 2020-04-28T16:09:42.778+0800: 1112.411: [ParNew: 2567977K->56794K(2831168K), 0.01
90506 secs] 3999542K->1491602K(5976896K), 0.0197083 secs] [Times: user=0.24 sys=0.01, real=0.02 secs] 
2020-04-28T16:09:43.698+0800: 1113.331: [CMS-concurrent-sweep: 1.579/1.609 secs] [Times: user=5.35 sys=2.34, real=1.61 secs] 
2020-04-28T16:09:43.699+0800: 1113.332: [CMS-concurrent-reset-start]
2020-04-28T16:09:43.707+0800: 1113.339: [CMS-concurrent-reset: 0.008/0.008 secs] [Times: user=0.03 sys=0.00, real=0.01 secs]

相关文章

  • 系统压测FullGC日志分析

    应用背景分析 压测一个业务系统,其中JVM堆内存参数如下,堆内存设置了6g,新生代3g,老年代相应的为3g,采用了...

  • 后端架构的套路

    完善的监控系统流量预估与压测日志收集与分析分布式计划任务性能优化的思路服务治理的实现轻巧的发布系统 从前端请求到后...

  • 生产环境某个请求慢,可以这样排查.Arthas利器

    这段时间在做产品的性能测试,一直达不到压测指标,而且远高于压测指标数据。通过系统运行日志,只能体现某个模块耗时长,...

  • 性能压测学习大纲

    一、压测的目的 二、压测的完整流程 三、压测场景分析/组织测试脚本 四、压测数据准备 五、压测指标监控 七、压测结...

  • 服务端压测简介

    单系统压测与全链路压测 为什么只做单系统压测还不够呢? 在活动开始的瞬间,各系统都面临自身服务的巨大的压力,而系统...

  • 系统压测

    1、基础概念系统QPS、并发请求数关系、响应时间 1.1、响应时间 响应时间是一个系统最重要的指标之一,它的数值大...

  • 提升cpu使用率

    如何优化压测工具发压能力 -- 提升cpu使用率 压测工具工作流程 压测工具一般在性能压测过程中用于对被压的系统产...

  • Jmeter性能测试基础

    阅读目录 压测任务需求的确认 压测设置 压测结果查看 压测结果的分析 压力测试   压力测试分两种场景:一种是单场...

  • 全链路压测汇总思路

    简介 发压场景设计执行(压测建模-单系统-类-方法-数据存储/多系统-业务场景保真),-> 压测平台的实现 -> ...

  • 业务系统 Over 阿里云性能压测的最佳实践

    业务系统性能压测的最佳实践 压测工具的选择 目前主流的压测工具有 ab Jmeter 阿里云PTS 如何来选择呢,...

网友评论

    本文标题:系统压测FullGC日志分析

    本文链接:https://www.haomeiwen.com/subject/rxezphtx.html