首页 > 其他分享 >CMS垃圾收集器深入解析

CMS垃圾收集器深入解析

时间:2024-05-03 23:56:13浏览次数:27  
标签:标记 对象 收集器 并发 线程 垃圾 解析 CMS

CMS本身是个非常极端的垃圾收集器,他过于注重停顿时间,而不在乎吞吐量。正常情况使用标记清除算法,所以也会有内存碎片的产生,整个CMS垃圾收集的过程,主要是为了缩短停顿时间,所以在有些环节会与业务线程并发执行。

1.初始标记,根据GC Root的引用链,只标记第一个对象,此时是多个标记线程并行处理(jdk8默认多线程 jdk7默认单线程 我本人倾向单线程)。STW
2.并发标记:根据第一个对象的引用链并发标记,并发是与业务线程的并发,所以会有一个问题,有的垃圾对象可能因为并发的业务线程而重新引用了,此时却被CMS列为垃圾对象
3.重新标记:把没标记的对象(垃圾对象) 修改为可用对象,因为这个时候你不能百分百确定它是不是垃圾对象,所以保留,重新标记是扫描整个堆,此时STW
4.并发清除:与业务线程同时并发进行,清除垃圾,也正是因为与业务线程并发,此时还是会产生垃圾。

为什么初始标记的时候用单线程标记,而重新标记的时候用多线程标记?
CMS的主要目的是为了减少停顿时间,但还有个问题需要考虑到,应该合理的利用资源,而不是浪费资源,初始标记的过程很简单,只需要根据GC Root的引用链标记第一个对象,效率很高,没有必要用多线程,而重新标记的时候,因为是要把整个引用链上的对象又重新标记一遍,所以使用多线程,重新标记用多线程肯定比用单线程要快。所有的垃圾收集器不仅在强调吞吐量和停顿时间,还有一个就是需要合理的利用资源。
在jdk7中 初始标记默认是单线程,因为本身用jdk7的 多线程也用的不多,而jdk8中 初始标记默认变成多线程,因为用jdk8的多线程用的多
-XX:+CMSParallelInitialMarkEnabled控制是否开启

![[CMS垃圾回收流程.png]]
CMS 采用的算法: 正常情况使用标记清除算法 forkground(并发失败)的时候使用标记压缩,
用标记压缩算法是用的
单次遍历算法(减少回收次数) + Lisp2滑动整理算法(增大回收面积)

-XX:+UseCMSCompactAtFullCollection
-XX:CMSFullGCsBeforeCompaction=0
这两个参数表示多少次FullGC后采用MSC算法压缩堆内存,0表示每次FullGC后都会压缩,同时0也是默认值
标记压缩算法是通过参数控制是否启用的,
碎片问题也是CMS采用的标记清理算法最让人诟病的地方:Backgroud CMS采用的标记清理算法会导致内存碎片问题,从而埋下发生FullGC导致长时间STW的隐患。

所以如果触发了FullGC,无论是否会采用MSC算法压缩堆,那都是ParNew+CMS组合非常糟糕的情况。因为这个时候并发模式已经搞不定了,而且整个过程单线程,完全STW,可能会压缩堆(是否压缩堆通过上面两个参数控制),真的不能再糟糕了!想象如果这时候业务量比较大,由于FullGC导致服务完全暂停几秒钟,甚至上10秒,对用户体验影响得多大。

1.初始标记 2.并发标记 3.并发预处理 4.可终止的预处理 5.重新标记 6.并发清理

已知CMS是回收老年代对象,
![[CMS引用对象如何判断A对象是存活对象-问题.png]]

初始标记的时候,是STW, 并发标记是和业务线程并行阶段,这个时候如果老年代区已经满了,而业务线程又有其他的老年代对象需要放入Old区,这个时候是放不进去的,问题产生了,此时就会触发CMS的Foregroud CMS,按照官方的描述就是:如果并发收集器不能在老年代区域被填满之前回收完垃圾,或者说年老代中有效的空闲内存空间不能满足某个内存的分配请求,此时应用会暂停,这种暂停才是CMS最致命的问题,暂停的这段时间内开始垃圾回收,直到回收完成才会恢复应用程序,这就是CMS的并发失败,在并发失败之后会使用标记压缩算法

并发预处理:CMS的主要目的是尽可能少的停顿时间,那么如果新生代的对象少了,CMS根据老年代去找的新生代对象也就少了,这样CMS回收的速度也就变快了
并发预处理就是并发标记之后,再执行一次新生代的垃圾回收,并发预处理是为重新标记提前做好准备,减少重新标记的时间,98%的新生代对象朝生夕死,执行完一次新生代对象的回收之后,重新标记的效率将大大提高。

记忆集

记忆集是一种用于记录从非收集区域指向收集区域的指针集合的数据结构
比如老年代的对象如果在GCRoot上,那么这个对象就可以看成一个GCRoot,
他只要指向一个新生代,那么这个新生代就不用回收啦,这种指向关系,我们需要存储。卡表 稀疏表 粗粒度位图 细粒度位图都属于记忆集、

记忆集的实现方式有很多 哈希表 位图 粗粒度位图 细粒度位图 单纯的字节数组。。。

卡表CardTable

卡表就是记忆集的实现方式之一,在CMS当中,记录老年代引用新生代这种指向关系的数组 卡表就是个字节数组。

[byte1, byte2, byte3, byte4]
每个元素可称之为卡页,一个卡页描述的是512个字节的老年代区域内存地址,类似于位图的概念,每个元素都是一个字节,一个字节占8bit位, 这8个bit位 每一个位置都是用来标识的,00000000 当这8个标志位某个位置的0变为1的时候,说明变成了脏卡,0变成1说明该元素代表的Old区中的512个字节中的某个对象有跨代引用的关系,可能是老年代指向新生代,也有可能是新生代指向老年代,8个标志位都代表不同的含义。所以在重新标记的时候,只要扫描Old区的变脏的元素加入GCRoot中就行,

三色标记:
1.初始时,所有对象都在白色集合当中
2.将GC Root直接引用到的对象 挪到灰色集合当中,(初始标记只找每个GC Root中的第一个对象)
3.从灰色集合中获取对象,
4.将本对象 引用到的其他对象全部挪到灰色集合中,
5.将本对象挪到黑色集合当中
重复3,4步骤,直到灰色集合为空时结束
结束后 仍然在白色集合中的对象为不可达对象,回收

多标:在并发标记的时候,因为业务线程也在运行,此时可能会因为业务线程的开始或者结束而导致 有新的对象的产生,或者有新的垃圾对象,此时这种对象是一律当作可用对象(浮动垃圾) 不做清理的,留着下一次再清理。并发清理的时候也会有这种现象。

漏标:漏标?

写屏障

伪共享

标签:标记,对象,收集器,并发,线程,垃圾,解析,CMS
From: https://www.cnblogs.com/zyonghua/p/18171852

相关文章

  • std::move 和 std::forward源码解析
    std::move和std::forward仅仅是执行转换(cast)的函数(事实上是函数模板)。std::move无条件的将它的实参转换为右值,而std::forward只在特定情况满足时下进行转换。std::movetemplate<class_Ty>constexprremove_reference_t<_Ty>&&move(_Ty&&_Arg)noexcept{returnstatic......
  • Keil FLM文件解析
    1.*.FLM的本质其实就是*.axf,它也是一段可执行代码。2.它是ARM工具链的一部分,/***********************************************************************//*ThisfileispartoftheARMToolchainpackage*//*Copyright(c)2010Keil-AnARMC......
  • C语言解析FLM(ELF)格式文件
    代码下载:https://gitee.com/jhembedded/flmparse 写这篇博客的目的是因为最近在做一个STM32的离线编程器,离线下载需要用到FLM文件的下载算法,所以实现了一下提取FLM文件中下载算法的C程序。有关ELF格式的详细说明可查看这个文件:http://flint.cs.yale.edu/cs422/doc/ELF_Format.......
  • raft算法和etcd代码解析-5.应用模块的启动
    Node接口Node是raft应用模块在节点上的抽象,也是应用模块和算法模块交互的入口应用模块持有Node作为算法模块的引用,通过调用Node接口的API与算法模块通信,通信方式是通过若干个Channel异步完成的。//Noderepresentsanodeinaraftcluster.typeNodeinterface{ //告知......
  • 玄学野路子项目,探秘解析
    玄学这玩意太暴利,很难掌握度,稍不注意干大了,就容易踩缝纫机。但是很多人耐不住心里痒痒,因为这破玩意太他妈赚钱了。如果实在想搞,胆子又小,那就卖点小道具,几十块的东西,别人也懒得搭理咱。比如这个: 这个直播间打造的真是绝了,整个直播间的场景和话术,没有任何涉及封建迷信的地方。......
  • windows密码存储以及hashdump所得信息解析
    1.windows登录的明文密码,存储过程是怎么样的,密文存在哪个文件下,该文件是否可以打开,并且查看到密文在Windows中密码通常不会以明文形式存储。系统会通过保存密码的哈希值来确保安全性。这个过程涉及到NTLM或Kerberos身份认证协议,它们负责加密存储密码。以下是存储过程的简要说......
  • js逆向实战之某证信Accept-Enckey参数加密解析
    url:https://webapi.cninfo.com.cn/#/marketDataDate分析过程抓包,主要关注图中标记的数据包,它的回显数据是我们所需要的。但在该数据包的请求中有一个Accept-Enckey参数是经过加密的,需要知道其加密的逻辑。全局搜索sysapi/p_sysapi1007,只有一处符合的。找到对应地方,......
  • 快速了解Django:核心概念解析与实践指南
    title:快速了解Django:核心概念解析与实践指南date:2024/5/120:31:41updated:2024/5/120:31:41categories:后端开发tags:Django核心路由系统视图系统ORM管理中间件Web框架登录装饰器第一章:Django简介背景和发展历程:Django是一个开放源代码的Web应用框架......
  • 基于Hyperf的CMS,企业官网通用php-swoole后台管理系统
    2023年9月11日10:47:00仓库地址:https://gitee.com/open-php/zx-hyperf-cmsCMS,企业官网通用PHP后台管理系统框架介绍hyperfSCUI后端开发组件php8.1hyperf3.1数据库sql(使用最新日期文件)hyperf\doc\sql_bakmysql8.系统默认账号密码:admin/admin前端开发组件scui......
  • Spring6 当中 Bean 的生命周期的详细解析:有五步,有七步,有十步
    1.Spring6当中Bean的生命周期的详细解析:有五步,有七步,有十步@目录1.Spring6当中Bean的生命周期的详细解析:有五步,有七步,有十步每博一文案1.1什么是Bean的生命周期1.2Bean的生命周期"五步"1.3Bean的生命周期“七步”1.4Bean的生命周期“十步”2.Bean的作用域不......