`
无量
  • 浏览: 1148111 次
  • 性别: Icon_minigender_1
  • 来自: 杭州
社区版块
存档分类
最新评论

JVM调优:选择合适的GC collector (三)

 
阅读更多

CMS Collector 

在很多地方,CMS Collector常被翻译成“并发”,而ParallelGC被称为“并行”,但中文里,这两词的区分度并不明显。事实上,所谓的Parallel是指,在执行GC的时候将会有多个GC线程共同工作,但是,在执行GC的过程中仍然是“stop-the-world”。CMS的区别在于,在执行GC的时候,GC线程是不需要暂停application的线程,而是和它们“并发”一起工作。
所以,采用CMS的原因就在于它可以提供最低的pause time。

回到CMS的示意图:

 

这张图表示的是CMS在执行Full GC的过程,这个过程包括了6个步骤:
# STW initial mark
# Concurrent marking
# Concurrent precleaning
# STW remark
# Concurrent sweeping
# Concurrent reset

STW表示的意思就是“stop-the-world”。
所以,CMS也并不是完全不会暂停application的,在这六个步骤中,有两个步骤需要STW,分别是:initial mark和remark(如图所示)。而其它的四个步骤是可以和application“并发”执行。initial mark是由一个GC thread来执行,它的暂停时间相对比较短。而remark过程的暂停时间要比initial mark更长,且通常由多个thread执行。
这六个步骤的具体内容我就不写了(其实俺也似懂非懂),有兴趣的可以参考【1】,【2】。

 

接下来看看实验结果。

 

实验结果

 

JVM参数如下:

Java -jar -Xms10g -Xmx15g -XX:+UseConcMarkSweepGC -XX:NewSize=6g -XX:MaxNewSize=6g -verbose:gc -XX:+PrintGCDetails -XX:+PrintGCTimeStamps  -Xloggc:./log/gc.log Slaver.jar

 

 

从图中可以看出,采用CMS Collector的最大的不同在于它已经没有了那个“大峡谷”,意味着发生的Full GC并没有导致系统的throughput降低到0。虽然图中也有几次曲线的下降(事实上,这就是发生Full GC的地方),但是曲线的下降很微弱,并且,持续时间也不太长。
整体而言,系统的平均throughput大概在7000 – 6000 request/sec之间,要比Serial GC好,但略低于Parallel GC。

看一个Minor GC的log:
519.514: [GC 519.514: [ParNew: 5149852K->83183K(5662336K), 0.0831770 secs] 6955196K->1905793K(9856640K), 0.0833560 secs] [Times: user=0.57 sys=0.03, real=0.08 secs ] 
采用CMS GC在发生Minor GC的时候采用的collector类似于Parallel GC,log也和Parallel GC的log类似。不多解释。

 

重点在于Full GC的log:
2051.800: [GC [1 CMS-initial-mark : 6040466K(6555784K)] 6161554K(12218120K), 0.1028810 secs] [Times: user=0.10 sys=0.00, real=0.11 secs ] 
2051.903: [CMS-concurrent-mark-start ]
2059.492: [GC 2059.492: [ParNew: 5153779K->129958K(5662336K), 0.1145560 secs] 11194245K->6189004K(12218120K), 0.1147330 secs] [Times: user=0.82 sys=0.04, real=0.11 secs] 
2067.229: [GC 2067.229: [ParNew: 5163174K->92868K(5662336K), 0.1136260 secs] 11222220K->6170498K(12218120K), 0.1137820 secs] [Times: user=0.82 sys=0.00, real=0.12 secs] 
2075.005: [GC 2075.005: [ParNew: 5126084K->126301K(5662336K), 0.1205450 secs] 11203714K->6222479K(12218120K), 0.1207120 secs] [Times: user=0.84 sys=0.01, real=0.12 secs] 
2077.487: [CMS-concurrent-mark: 25.231/25.584 secs] [Times: user=158.91 sys=22.71, real=25.58 secs ] 
2077.487: [CMS-concurrent-preclean-start ]
2078.512: [CMS-concurrent-preclean: 0.961/1.025 secs] [Times: user=5.97 sys=1.20, real=1.03 secs] 
2078.513: [CMS-concurrent-abortable-preclean-start]
2082.466: [GC 2082.467: [ParNew: 5159517K->89444K(5662336K), 0.1162740 secs] 11255695K->6204092K(12218120K), 0.1164340 secs] [Times: user=0.82 sys=0.01, real=0.12 secs] 
 CMS: abort preclean due to time 2083.642: [CMS-concurrent-abortable-preclean: 4.933/5.129 secs] [Times: user=31.10 sys=4.89, real=5.12 secs] 
2083.644: [GC[YG occupancy: 877128 K (5662336 K)]2083.644: [Rescan (parallel) , 0.5058390 secs]2084.150: [weak refs processing, 0.0000630 secs] [1 CMS-remark: 6114647K(6555784K)] 6991776K(12218120K), 0.5060260 secs] [Times: user=3.35 sys=0.01, real=0.50 secs ] 
2084.150: [CMS-concurrent-sweep-start ]
2090.416: [GC 2090.416: [ParNew: 5122660K->124614K(5662336K), 0.1247190 secs] 11237258K->6257803K(12218120K), 0.1248800 secs] [Times: user=0.88 sys=0.00, real=0.12 secs] 
2095.868: [CMS-concurrent-sweep: 11.593/11.718 secs] [Times: user=70.11 sys=11.53, real=11.72 secs] 
2095.896: [CMS-concurrent-reset-start ]
2096.124: [CMS-concurrent-reset: 0.227/0.227 secs] [Times: user=1.33 sys=0.19, real=0.23 secs]
 

Full GC的log和其它的collector完全不同,简单解释一下:
log的第一行CMS-initial-mark 表示CMS执行它的第一步:initial mark。它花费的时间是real=0.11 secs,由于这一步骤是STW的,所以整个application被暂停了0.11秒。并且,user time和real time相差不大,所以确实是只有一个thread执行这一步;
CMS-concurrent-mark-start 表示开始执行第二步骤:concurrent marking。它执行时间是real=25.58 secs,但因为这一步是可以并发执行的,所以系统在这段时间内并没有暂停;
CMS-concurrent-preclean-start 表示执行第三步骤:concurrent precleaning。同样的,这一步也是并发执行;
最重要的是这一条语句:
2083.644: [GC[YG occupancy: 877128 K (5662336 K)]2083.644: [Rescan (parallel) , 0.5058390 secs]2084.150: [weak refs processing, 0.0000630 secs] [1 CMS-remark: 6114647K(6555784K)] 6991776K(12218120K), 0.5060260 secs] [Times: user=3.35 sys=0.01, real=0.50 secs] 
这一步是步骤:remark的执行结果,它的执行时间是real=0.50 secs。因为这是STW的步骤,并且它的pause time一般是最长的,所以这一步的执行时间会直接决定这次Full GC对系统的影响。这次只执行了0.5秒,系统的throughput未受太大影响。
后面的log分别记录了concurrent-sweep和concurrent-reset。就不多说了,更详细的log分析可见【3】。

 

结论 

比较了这几种Collector,发现CMS应该是最适合我的系统的。因为它并不会因为Full GC而在未来的某一时刻突然停滞工作。这一点其实在很多系统中都是非常重要的,比如Web Server ....

 

多说一点 

贴另外两张实验结果图:

 

 

这两张图也是采用CMS Collector实验得到的。区别在于使用了不同的参数。第一张图是CMS Collector采用了incremental model的方式:
java -jar -Xms10g -Xmx15g -XX:+UseConcMarkSweepGC -XX:+CMSIncrementalMode -XX:NewSize=6g -XX:MaxNewSize=6g -verbose:gc -XX:+PrintGCDetails -XX:+PrintGCTimeStamps -XX:+PrintHeapAtGC -Xloggc:./log/gc.log Slaver.jar 

而第二张图则调整了AbortablePrecleanTime的值:
java -jar -Xms10g -Xmx15g -XX:+UseConcMarkSweepGC -XX:CMSMaxAbortablePrecleanTime=15   -XX:NewSize=6g -XX:MaxNewSize=6g -verbose:gc -XX:+PrintGCDetails -XX:+PrintGCTimeStamps  -Xloggc:./log/gc.log Slaver.jar 

这两个参数有什么用不多解释,只是想说明,即便选择了合适的Collector,也可能由于其它参数的设置而产生巨大差异。

JVM的调优确实不简单。这个并没有绝对的准则或者公式,唯一的好办法就是实验。

( The End ) 

 

Reference: 

 

【1】Did You Know ... 
【2】Java SE 6 HotSpot[tm] Virtual Machine Garbage Collection Tuning 
【3】Understanding CMS GC Logs 

分享到:
评论

相关推荐

    马士兵jvm调优笔记.docx

    ### 马士兵JVM调优笔记知识点梳理 #### 一、Java内存结构 Java程序运行时,其内存被划分为几个不同的区域,包括堆内存(Heap)、方法区(Method Area)、栈(Stack)、程序计数器(Program Counter Register)以及...

    jvm调优测试仓库-jvm-monitor.zip

    三、JVM调优实践 1. 堆内存调整:根据应用的内存需求,合理设定堆大小,避免Full GC频繁发生。 2. GC调优:选择适合应用的垃圾收集器,调整GC参数以减少停顿时间或提高吞吐量。 3. 线程优化:监控线程状态,减少...

    Java面试题-内存+GC+类加载器+JVM调优.pdf

    "Java面试题-内存+GC+类加载器+JVM调优" 在 Java 面试中,内存、GC、类加载器和 JVM 调优是非常重要的知识点,本文将对这些知识点进行详细的解释和分析。 一、Java 内存模型 在 Java 中,内存主要分为两部分:堆...

    jvm 调优建议文档

    ### jvm调优建议文档知识点解析 #### 一、JVM基本概念及组成部分 - **JVM内存区域划分**:JVM内存分为新生代、老年代以及元空间(Metaspace)三大区域。其中,新生代负责存放新创建的对象,经过多次垃圾回收后存活的...

    JVM_GC调优

    ### JVM_GC调优详解 #### 一、JVM体系结构概览 Java虚拟机(JVM)作为Java程序的运行环境,其内部结构复杂且高效。为了更好地理解JVM_GC调优,我们首先来了解一下JVM的基本组成部分。 1. **类装载器子系统(Class ...

    JVM调优总结与ava虚拟机:JVM高级特性与最佳实践(最新第二版)

    理解不同类型的GC工作原理、触发条件以及如何选择合适的GC策略对于减少系统停顿时间至关重要。 3. **内存分配与GC调优**:包括对象的分配策略、新生代与老年代的划分、内存大小调整、存活对象的判断算法(如Mark-...

    JVM基础知识及性能调优

    - **选择合适的垃圾回收器**:根据应用的特点选择不同的GC策略,如CMS、G1等。 - **监控工具**:利用VisualVM、JConsole等工具监控JVM的运行状态,分析GC行为。 - **GC日志分析**:通过配置日志参数(`-XX:+...

    jMM+JVM-GC COLLECTOR+调优.pptx

    一个PPT包含 java内存模型,class运行机制。 java jvm垃圾回收算法 java jvm gc常见垃圾回收算法分析 java jvm调优

    用于测试jvm gc调优-share-jvm-gc.zip

    3. **监控和诊断**:使用JDK自带的JConsole、VisualVM或者第三方工具如JProfiler、YourKit等,监控JVM的内存使用、GC频率和暂停时间,找出性能瓶颈。 4. **对象生命周期管理**:优化代码,避免创建过多短生命周期的...

    JVM体系结构与GC调优

    每种算法在不同场景下有不同的性能表现,需要根据应用需求选择合适的GC。 2. **内存分配策略**:调整新生代、老年代、永久代(或元空间)的大小,以平衡吞吐量和响应时间。过大可能导致内存浪费,过小可能导致频繁...

    基于JVM 调优的技巧总结分析

    其次,选择合适的垃圾收集器(Garbage Collector,简称GC)对性能影响很大。不同类型的GC适用于不同的应用场景。例如,Serial Collector适合单线程环境,Parallel Collector适用于多CPU环境,可以提高并行收集的效率...

    JVM内存调优深入文章共享

    2. **选择合适的垃圾收集器**:考虑系统资源和应用特点,如响应时间优先或吞吐量优先。 3. **监控和分析GC日志**:通过`-XX:+PrintGCDetails`等选项输出GC日志,分析垃圾回收行为。 4. **减少Full GC**:优化对象...

    JVM参数参数调优共11页.pdf.zip

    选择合适的GC策略至关重要,如低延迟场景下通常使用CMS或G1。 - **GC日志**:开启-XX:+PrintGCDetails和-XX:+PrintGCDateStamps,以便分析和优化。 3. **类加载机制** - **类加载器**:Bootstrap、Extension、...

    jvm gc

    5. **JVM调优**:通过调整JVM参数,可以控制GC的行为,例如设置堆大小、新生代和老年代的比例、GC策略等。常用的JVM参数有`-Xms`, `-Xmx`, `-Xmn`, `-XX:NewRatio`, `-XX:SurvivorRatio`, `-XX:+UseConcMarkSweepGC`...

    JVM性能调优监控工具jps、jstack、jmap、jhat、jstat使用详解.docx

    JVM性能调优监控工具jps、jstack、jmap、jhat、jstat使用详解 本文将对一些常用的 JVM 性能调优监控工具进行介绍,包括 jps、jstack、jmap、jhat、jstat 等工具的使用详解。这些工具对于 Java 程序员来说是必备的,...

    JVM内存管理、调优与监控考据

    JVM调优还包括对垃圾收集器(Garbage Collector,GC)的选择和参数调整。不同类型的GC有不同的性能特征,如Serial GC适合轻量级应用,Parallel GC和Concurrent Mark Sweep (CMS) GC适用于高并发场景,G1 GC则试图...

    JVM内存设置与调优指南

    在Java世界中,Java虚拟机(JVM)是运行所有Java应用程序的核心。JVM内存设置与调优是提升应用性能的...理解内存结构、选择合适的垃圾收集器、合理设置参数,并结合监控工具进行调优,是优化Java应用性能的关键步骤。

    2024年java面试题-jvm性能调优面试题第二部分

    JVM性能调优涉及到对内存模型的理解、垃圾收集机制的选择与优化等多个方面。通过对这些知识点的深入掌握,开发者可以更好地应对实际开发中的性能问题,提高系统的稳定性和响应速度。此外,熟练运用各种调试工具也是...

Global site tag (gtag.js) - Google Analytics