博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
CMS垃圾回收机制
阅读量:4460 次
发布时间:2019-06-08

本文共 2126 字,大约阅读时间需要 7 分钟。

简介

Concurrent Mark Sweep,是一款基于并发、使用标记清除算法的垃圾回收算法,只针对老年代进行垃圾回收。CMS收集器工作时,GC工作线程和用户线程可以并发执行,以达到降低STW时间的目的。

开起VM选项-XX:+UseConcMarkSweepGC,表示对老年代的回收采用CMS。

生产环境中常用的两种垃圾收集器(ParNew:年轻代,CMS:老年代)

CMS维度

根据GC的触发机制分为:周期性Old GC(被动)和主动Old GC

一般都是被动GC,这里主要说的也是这个。

主动Old GC的过程,触发条件比较苛刻:

  • YGC过程发生Promotion Failed,进而对老年代进行回收
  • 比如执行了System.gc(),前提是没有参数ExplicitGCInvokesConcurrent

如果触发了主动Old GC,这时周期性Old GC正在执行,那么会夺过周期性Old GC的执行权(同一个时刻只能有一种在Old GC在运行),并记录 concurrent mode failure或者 concurrent mode interrupted

CMS收集器特点

  • 尽可能降低停顿
  • 会影响系统整体吞吐量和性能。比如,在用户线程运行过程中,分一半CPU去做GC,系统性能在GC阶段,反应速度就下降一半。
  • 清理不彻底。因为在清理阶段,用户线程还在运行,会产生新的垃圾,无法清理。
  • 不能在空间快满时再清理,因为和用户线程一起运行。-XX:CMSInitiatingOccupancyFraction设置触发GC的阈值,如果不幸内存预留空间不够,就会引起concurrent mode failure。

STW

首先,我们需要厘清一个概念,即只有标记阶段才需要STW (Stop The World)。标记完成以后,需要清除的对象已经确定,无论此时是否产生新的垃圾,都不影响对这些对象的清理。也就是说,清除阶段是可以设计成和用户线程并发执行的。

JVM在暂停的时候,需要选准一个时机,由于JVM系统运行期间的复杂性,不可能做到随时暂停,因此引入了安全点(safepoint)的概念:程序只有在运行到安全点的时候,才可以暂停下来。HotSpot采用主动中断的方式,让执行线程在运行期轮询是否需要暂停的标志,若需要则中断挂起。HotSpot使用了几条短小精炼的汇编指令便可完成安全点轮询以及触发线程中断,因此对系统性能的影响几乎可以忽略不计。

可达性

可达性是指,如果一个对象会被至少一个程序中的可达对象通过直接或间接的方式引用,则称该对象是可达的。更详细地说,一个对象满足一下两个条件之一,即被判定为可达的。

1.本身是根对象。根(root)是指由堆以外空间访问的对象。JVM会将以下对象标记为根:a.虚拟机栈(栈帧中的本地变量表)中引用的对象;b.方法区中的类静态属性引用的对象;c.方法区中的常量引用的对象;d.本地方法栈中JNI的引用对象。

2.被一个可达的对象引用。

CMS的几个阶段

CMS将可达性分析分解成两个阶段:a.仅扫描与根节点直接关联的对象; b.继续向下扫描完所有对象。因此,标记阶段也被拆分成两个阶段,即初始标记并发标记

CMS完整的收集过程如下:

  1. 初始标记(init-mark):仅扫描与根节点直接关联的对象并标记,这个阶段必须STW, 由于跟节点数量有限,所以这个过程非常短暂。

  2. 并发标记(concurrent-marking):与用户线程并发标记。这个阶段在初始标记的基础上继续向下追溯标记。在并发标记阶段,用户线程和标记线程并发执行,所以用户不会感受到停顿。

    **遍历第一个阶段(Init Mark)标记出来的存活对象,继续递归遍历老年代,并标记可直接或间接到达的所有老年代存活对象在这个阶段,发生变化的对象标记为Dity**

  3. 并发预清理(concurrent-precleaning):与用户线程并发进行。在并发标记阶段一些对象的引用已经发生了变化,precleaning会发现这些引用关系的改变,并将存活的对象标记。举个例子:如果线程A有一个指向对象X的引用,并将该引用传递给了线程B,CMS需要记录下线程B持有了对象X,即使线程A已经不存在了。precleaning是为了减少下一阶段“重新标记”的工作量,因为remark阶段会STW

    将会重新扫描前一个阶段标记的Dirty对象,并标记被Dirty对象直接或间接引用的对象

  4. 重新标记(remark)remark阶段会STW。如果应用正在并发运行且在不断地改变对象引用,CMS则不能准确地确定某个对象是否存活。所以CMS会在remark阶段STW,从而获取所有引用关系的改变。

  5. 并发清理(concurrent-sweeping):清理垃圾对象,这个阶段GC线程和用户线程并发执行。

  6. 并发重置(concurrent-reset):重置CMS收集器的数据结构,做好下一次执行GC任务的准备工作。

443934-20190227182123458-1570717662.png

可以看出,一个存在2次的STW

参考:

)

转载于:https://www.cnblogs.com/hongdada/p/10445686.html

你可能感兴趣的文章
SpringAOP用到了什么代理,以及动态代理与静态代理的区别
查看>>
利用STM32CubeMX来生成USB_HID_Mouse工程【添加ADC】(1)
查看>>
【leetcode】Populating Next Right Pointers in Each Node
查看>>
获取请求参数乱码的问题
查看>>
代码实现:判断E盘目录下是否有后缀名为.jpg的文件,如果有,就输出该文件名称...
查看>>
Android客户端测试点
查看>>
Jquery:怎样让子窗体的div显示在父窗体之上
查看>>
01概率
查看>>
Shell脚本
查看>>
MatLab Load cv::Mat 导入数据
查看>>
html+css相关笔记(一)
查看>>
基于块流协议保证音频优先发送
查看>>
关于互联网的一些数据
查看>>
数据预处理:独热编码(One-Hot Encoding)
查看>>
python将对象名的字符串类型,转化为相应对象的操作方法
查看>>
【NLP新闻-2013.06.03】New Book Where Humans Meet Machines
查看>>
mongodb安装4.0(rpm)
查看>>
DispatcherServlet的url mapping为“/”时,对根路径访问的处理
查看>>
备忘pwnable.kr 之passcode
查看>>
好久没敲代码了,手有点生——一个小小的时钟
查看>>