JVM CMS GC算法解析

本文涉及的产品
公共DNS(含HTTPDNS解析),每月1000万次HTTP解析
全局流量管理 GTM,标准版 1个月
云解析 DNS,旗舰版 1个月
简介: JVM CMS GC算法解析

CMS,全称Concurrent Low Pause Collector,是jdk1.4后期版本开始引入的新gc算法,在jdk5和jdk6中得到了进一步改进,它的主要适合场景是对响应时间的重要性需求 大于对吞吐量的要求,能够承受垃圾回收线程和应用线程共享处理器资源,并且应用中存在比较多的长生命周期的对象的应用。CMS是用于对Old+Perm回收,采用CMS时候,新生代必须使用Serial GC或者ParNew GC两种。目标是尽量减少应用的暂停时间,减少Full   GC发生的几率,利用和应用程序线程并发的垃圾回收线程来标记清除年老代。作为ARPG游戏服务器的应用,因为有永久缓存的存在,并且对于玩家操作响应时间也有非常高的要求(12+W/s 数据包),因此希 望能使用CMS来替代默认的server型JVM使用的并行收集器(Parallel MSC),以便获得更短的垃圾回收的暂停时间,提高程序的响应性。
CMS收集周期
CMS并非没有暂停,而是用两次短暂停来替代串行标记整理算法的长暂停,它的收集周期是这样:
初始标记(CMS-initial-mark) -> 并发标记(CMS-concurrent-mark) ->并发预清理(concurrent pre-clean)-> 重新标记(CMS-remark) -> 并发清除(CMS-concurrent-sweep) ->并发重设状态等待下次CMS的触发(CMS-concurrent-reset)。
其中的1,4两个步骤需要暂停所有的应用程序线程的。
第一次暂停从root对象开始标记存活的对象,这个阶段称为初始标记;第二次暂停是在并发标记之后,暂停所有应用程序线程,重新标记并发标记阶段遗漏的对象(在并发标记阶段结束后对象状态的更新导致)。第一次暂停会比较短,第二次暂停通常会比较长,并且 remark这个阶段可以并行标记。
而并发标记、并发清除、并发重设阶段的所谓并发,是指一个或者多个垃圾回收线程和应用程序线程并发地运行,垃圾回收线程不会暂停应用程序的执行,如果你有多于一个处理器,那么并发收集线程将与应用线程在不同的处理器上运行,显然,这样的开销就是会降低应用的吞吐量。Remark阶段的并行,是指暂停了所有应用程序后,启动一定数目的垃圾回收进程进行并行标记,此时的应用线程是暂停的。
CMS的young generation的回收采用的仍然是并行复制收集器,这个跟Parallel gc算法是一致的。


一段正常的CMS的日志,CMS的周期一般包含以下步骤:

========初始标记(CMS-initial-mark)============
2015-10-10T19:22:19.472+0800: 904337.364: [GC [1 CMS-initial-mark: 1996330K(2124800K)] 2089808K(3270400K), 0.0667700 secs] [Times: user=0.06 sys=0.00, real=0.07 secs] 
各个数据依次表示标记前后old区的所有对象占内存大小[1996330K],old的capacity[2124800K],整个JavaHeap(不包括perm)所有对象占内存总的大小[2089808K],JavaHeap的capacity[3270400K]。
2015-10-10T19:22:19.538+0800: 904337.430: Total time for which application threads were stopped: 0.0674020 seconds
========并发标记(CMS-concurrent-mark)=========
2015-10-10T19:22:19.538+0800: 904337.430: [CMS-concurrent-mark-start]
2015-10-10T19:22:19.540+0800: 904337.432: Total time for which application threads were stopped: 0.0010340 seconds
2015-10-10T19:22:21.471+0800: 904339.363: [CMS-concurrent-mark: 1.931/1.932 secs] [Times: user=6.94 sys=0.30, real=1.93 secs]
========并发预清理(concurrent pre-clean)======
2015-10-10T19:22:21.471+0800: 904339.363: [CMS-concurrent-preclean-start]
2015-10-10T19:22:21.608+0800: 904339.500: [CMS-concurrent-preclean: 0.117/0.137 secs] [Times: user=0.15 sys=0.06, real=0.13 secs] 
2015-10-10T19:22:21.608+0800: 904339.500: [CMS-concurrent-abortable-preclean-start]CMS: abort preclean due to time 
2015-10-10T19:22:26.798+0800: 904344.690: [CMS-concurrent-abortable-preclean: 5.140/5.190 secs] [Times: user=7.10 sys=1.45, real=5.19 secs] 
=========重新标记(CMS-remark)=================
2015-10-10T19:22:26.799+0800: 904344.691: [GC[YG occupancy: 270973 K (1145600 K)]
2015-10-10T19:22:26.799+0800: 904344.691: [Rescan (parallel) , 0.2171280 secs]
2015-10-10T19:22:27.016+0800: 904344.908: [weak refs processing, 0.0000700 secs]
2015-10-10T19:22:27.016+0800: 904344.908: [scrub string table, 0.0016420 secs] [1 CMS-remark: 1996330K(2124800K)] 2267303K(3270400K), 0.2190720 secs] [Times: user=2.13 sys=0.00, real=0.22 secs] 
2015-10-10T19:22:27.021+0800: 904344.913: Total time for which application threads were stopped: 0.2232820 seconds
==========并发清除(CMS-concurrent-sweep)======
2015-10-10T19:22:27.022+0800: 904344.914: [CMS-concurrent-sweep-start]
2015-10-10T19:22:27.970+0800: 904345.862: [CMS-concurrent-sweep: 0.948/0.948 secs] [Times: user=1.53 sys=0.18, real=0.95 secs]
==========并发重设状态(CMS-concurrent-reset)==
2015-10-10T19:22:27.970+0800: 904345.862: [CMS-concurrent-reset-start]
2015-10-10T19:22:27.976+0800: 904345.868: [CMS-concurrent-reset: 0.005/0.005 secs] [Times: user=0.00 sys=0.00, real=0.00 secs]





其中可以看到CMS-initial-mark阶段暂停了0.0674020 seconds,而CMS-remark阶段暂停了0.2232820 seconds,因此两次暂停的总共时间是0.290684seconds,也就是290毫秒左右。两次短暂停的时间之和在300ms以下可以称为正常现象。



啥时候会触发CMS GC?



1、旧生代或者持久代已经使用的空间达到设定的百分比时(默认CMS是在tenured generation,也就是old区占满92%的时候开始进行CMS收集,

2、JVM自动触发(JVM的动态策略,也就是悲观策略)(基于之前GC的频率以及旧生代的增长趋势来评估决定什么时候开始执行),如果不希望JVM自行决定,可以通过-XX:UseCMSInitiatingOccupancyOnly=true来制定;

CMS GC因为是在程序运行时进行GC,不会暂停,所以不能等到不够用的时候才去开启GC,官方说法是他们的默认值是68%,但是可惜的是文档写错了,经过很多测试和源码验证这个参数应该是在92%的时候被启动,

-XX:CMSInitiatingOccupancyFraction=70

这样保证Old的内存在使用到70%的时候,就开始启动CMS了;如果你真的想看看默认值,那么就使用参数:-XX:+PrintCMSInitiationStatistics 这个变量只有JDK 1.6可以使用 1.5不可以,查看实际值-XX:+PrintCMSStatistics



reference:

The default for JVM 1.4.2 is 68%, but do NOT assume that the JVM always uses the default if you do not specify this parameter. Instead, analyze the GC logs to understand when the JVM triggers a CMS GC. we determined that a lot of objects were promoted to the tenured generation and CMS GC was mostly triggered at 50% occupancy of the tenured generation with some occurrences between 60% to 75% also


为啥CMS会有内存碎片,如何避免?

ygc变慢的原因通常是由于old gen出现了大量的碎片。

由于在CMS的回收步骤中,没有对内存进行压缩,所以会有内存碎片出现,CMS提供了一个整理碎片的功能,通过-XX:UseCMSCompactAtFullCollection 来启动此功能,启动这个功能后,默认每次执行Full GC的时候会进行整理,目前默认就是true了!(也可以通过-XX:CMSFullGCsBeforeCompaction =n来制定多少次Full GC之后来执行整理),整理碎片会stop-the-world.默认是0,也就是在默认配置下每次CMS GC顶不住了而要转入full GC的时候都会做压缩。  



啥时候会触发Full GC?

一、旧生代空间不足:java.lang.outOfMemoryError:java heap space;

二、Perm空间满:java.lang.outOfMemoryError:PermGen space;

三、CMS GC时出现promotion failed  和concurrent  mode failure(Concurrent mode failure发生的原因一般是CMS正在进行,但是由于old区内存不足,需要尽快回收old区里面的死的java对象,这个时候foreground gc需要被触发,停止所有的java线程,同时终止CMS,直接进行MSC。);

四、统计得到的minor GC晋升到旧生代的平均大小大于旧生代的剩余空间;

五、主动触发Full GC(执行jmap -histo:live [pid])来避免碎片问题;或者System.gc();



什么时候不应该用CMS?

heap小于3g不建议使用CMS GC



参考文章:

一次CMS GC问题排查过程(理解原理+读懂GC日志)

目录
相关文章
|
5天前
|
监控 算法 安全
内网桌面监控软件深度解析:基于 Python 实现的 K-Means 算法研究
内网桌面监控软件通过实时监测员工操作,保障企业信息安全并提升效率。本文深入探讨K-Means聚类算法在该软件中的应用,解析其原理与实现。K-Means通过迭代更新簇中心,将数据划分为K个簇类,适用于行为分析、异常检测、资源优化及安全威胁识别等场景。文中提供了Python代码示例,展示如何实现K-Means算法,并模拟内网监控数据进行聚类分析。
28 10
|
2天前
|
存储 监控 算法
探秘员工泄密行为防线:基于Go语言的布隆过滤器算法解析
在信息爆炸时代,员工泄密行为对企业构成重大威胁。本文聚焦布隆过滤器(Bloom Filter)这一高效数据结构,结合Go语言实现算法,帮助企业识别和预防泄密风险。通过构建正常操作“指纹库”,实时监测员工操作,快速筛查可疑行为。示例代码展示了如何利用布隆过滤器检测异常操作,并提出优化建议,如调整参数、结合日志分析系统等,全方位筑牢企业信息安全防线,守护核心竞争力。
|
23天前
|
存储 算法 安全
控制局域网上网软件之 Python 字典树算法解析
控制局域网上网软件在现代网络管理中至关重要,用于控制设备的上网行为和访问权限。本文聚焦于字典树(Trie Tree)算法的应用,详细阐述其原理、优势及实现。通过字典树,软件能高效进行关键词匹配和过滤,提升系统性能。文中还提供了Python代码示例,展示了字典树在网址过滤和关键词屏蔽中的具体应用,为局域网的安全和管理提供有力支持。
50 17
|
28天前
|
算法 搜索推荐 Java
【潜意识Java】深度解析黑马项目《苍穹外卖》与蓝桥杯算法的结合问题
本文探讨了如何将算法学习与实际项目相结合,以提升编程竞赛中的解题能力。通过《苍穹外卖》项目,介绍了订单配送路径规划(基于动态规划解决旅行商问题)和商品推荐系统(基于贪心算法)。这些实例不仅展示了算法在实际业务中的应用,还帮助读者更好地准备蓝桥杯等编程竞赛。结合具体代码实现和解析,文章详细说明了如何运用算法优化项目功能,提高解决问题的能力。
58 6
|
2月前
|
存储 算法 安全
基于红黑树的局域网上网行为控制C++ 算法解析
在当今网络环境中,局域网上网行为控制对企业和学校至关重要。本文探讨了一种基于红黑树数据结构的高效算法,用于管理用户的上网行为,如IP地址、上网时长、访问网站类别和流量使用情况。通过红黑树的自平衡特性,确保了高效的查找、插入和删除操作。文中提供了C++代码示例,展示了如何实现该算法,并强调其在网络管理中的应用价值。
|
2月前
|
机器学习/深度学习 人工智能 算法
深入解析图神经网络:Graph Transformer的算法基础与工程实践
Graph Transformer是一种结合了Transformer自注意力机制与图神经网络(GNNs)特点的神经网络模型,专为处理图结构数据而设计。它通过改进的数据表示方法、自注意力机制、拉普拉斯位置编码、消息传递与聚合机制等核心技术,实现了对图中节点间关系信息的高效处理及长程依赖关系的捕捉,显著提升了图相关任务的性能。本文详细解析了Graph Transformer的技术原理、实现细节及应用场景,并通过图书推荐系统的实例,展示了其在实际问题解决中的强大能力。
271 30
|
2月前
|
存储 监控 算法
企业内网监控系统中基于哈希表的 C# 算法解析
在企业内网监控系统中,哈希表作为一种高效的数据结构,能够快速处理大量网络连接和用户操作记录,确保网络安全与效率。通过C#代码示例展示了如何使用哈希表存储和管理用户的登录时间、访问IP及操作行为等信息,实现快速的查找、插入和删除操作。哈希表的应用显著提升了系统的实时性和准确性,尽管存在哈希冲突等问题,但通过合理设计哈希函数和冲突解决策略,可以确保系统稳定运行,为企业提供有力的安全保障。
|
2月前
|
存储 Java 开发者
浅析JVM方法解析、创建和链接
上一篇文章《你知道Java类是如何被加载的吗?》分析了HotSpot是如何加载Java类的,本文再来分析下Hotspot又是如何解析、创建和链接类方法的。
|
2月前
|
存储 监控 算法
Java虚拟机(JVM)垃圾回收机制深度解析与优化策略####
本文旨在深入探讨Java虚拟机(JVM)的垃圾回收机制,揭示其工作原理、常见算法及参数调优方法。通过剖析垃圾回收的生命周期、内存区域划分以及GC日志分析,为开发者提供一套实用的JVM垃圾回收优化指南,助力提升Java应用的性能与稳定性。 ####
|
3月前
|
缓存 Prometheus 监控
Elasticsearch集群JVM调优设置合适的堆内存大小
Elasticsearch集群JVM调优设置合适的堆内存大小
632 1

热门文章

最新文章

推荐镜像

更多