并发的标记—清除(Concurrent Mark Sweep,缩写为 CMS)收集器,使得在整个收集的过程当中只是很短的暂停应用的执行,可经过在 JVM 参数中设置-XX:UseConcMarkSweepGC 来使用此收集器,不过此收集器仅用于old和Perm(永生)的对象收集,并发的标记—清除较之Stop-The-World 的标记—清除复杂了不少,来看看:数组
并发标记—清除作到的是在标记访问每个节点时以及清除不活跃的对象时采用和应用并发的方式,仅需在初始化标记节点状态以及最终标记节点状态时须要暂停整个应用,所以其形成的应用的暂停的时间会比较的短。并发
并发标记—清除为了保证尽可能短的形成应用的暂停,首先从分配内存上作了改动,CMS提供了两个 free lists,一个用于存放小对象,另一个则用于存放大对象,当 JVM 须要给对象分配内存时,则经过 free list 来找到可用的堆地址,并进行内存的分配以及将此地址从 free
list 删除,当 CMS 回收对象内存后,则将其相应的地址从新放入此 free list 中,这样的好处是在回收对象的时候不须要作对象的移动等,所以可让回收过程并发的进行。jvm
接着来看看并发标记—清除的执行步骤:性能
1.Initial Marking --初始标记
此步须要暂停整个应用,JVM 扫描整个 old generation 中根对象可直接访问到的对象,并对这些对象进行标记,对于标记的对象 CMS 采用一个外部的 bit 数组来进行记录。spa
2. Concurrent Marking --并发标记
在初始化标记完毕后,CMS 恢复全部应用的线程,同时开始并发的对以前标记过的对象进行轮循,以标记这些对象可访问的对象。CMS 为了确保可以扫描到全部的对象,避免在 Initial Marking 中还有未标识到的对象,采用的方法为找到标记了的对象,并将这些对象放入 Stack 中,扫描时寻找此对象依赖的对象,若是依赖的对象的地址在其以前,则将此对象进行标记,并同时放入 Stack 中,如依赖的对象地址在其以后,则仅标记该对象。线程
在进行 Concurrent Marking 时 minor GC 也可能会同时进行,这个时候很容易形成旧生代对象引用关系改变,CMS 为了应对这样的并发现象,提供了一个 Mod Union Table 来进行记录,在这个 Mod Union Table 中记录每次 minor GC 后修改了的 Card 的信息。设计
在进行 Concurrent Marking 时还有可能会出现的一个并发现象是应用修改了旧生代中的对象的引用关系,CMS 中仍然采用 Card Table 的方式来进行记录,在 Card 中将某对象标识为 dirty 状态,但即便是这样仍然可能会出现一种现象致使再也不被引用的对象仍然是 marked的状态:3d
3.Final Marking -- 最终标记
此步须要暂停整个应用,因为在 Concurrent Marking 时应用可能会修改对象的引用关系或建立新的对象,所以须要把这些改变或新建立的对象也进行扫描,CMS 递归扫描 Mod Union Table 以及 Card Table 中 dirty 的对象,并进行标记。对象
4.Concurrent Sweeping -- 并发清除
在完成了 Final Marking 后,恢复全部应用的线程,就进入到这步了,这步须要负责的是将没有标记的对象进行回收。blog
回收过程是并发进行的,而 JVM 分配对象内存(尽管 CMS 仅用于 old generation,但有些时候会因为应用建立的对象过大致使直接分配到 old generation 的现象,另一种现象就是 young generation 通过回收后须要转入 old generation 的对象)和 CMS 释放内存又都是操
做 free list,会产生 free list 竞争的现象,所以 CMS 在此增长了 Mutual exclusion locks,以 JVM分配优先。
CMS 为了不每次回收后回收到的大小都比以前分配出去的内存小,在进行 sweeping的时候,还会尽可能的将相邻的块从新组装为一个块,sweeping 为了不和 JVM 分配对象内存产生冲突,采用的方法为首先从 free list 中删除块,组装完毕后再从新放入块中,为了可以从 free list 中删除指定的块,CMS 将 free list 设计为了双向链表。
总结:
CMS 中的耗时的过程都是和应用并发进行的,这也是 CMS 最突出的优势,使得其形成的应用的暂停时间比 Mark-Sweeping 的方式短了不少,但同时也意味着 CMS 会和应用线程争抢 CPU 资源, CMS 回收内存的方式也使得其很容易产生内存碎片,下降了空间的利用率,
另外就是 CMS 在回收时容易产生一些应该回收但须要等到下次 CMS 才能被回收掉的对象,例如上图中的 C 对象,称为“浮动垃圾“,这也就要求了采用 CMS 的状况下须要提供更多的可用的旧生代空间,整体来讲 CMS 很适用于对响应时间要求很高、CPU 资源竞争不是很激烈以及内存空间相对更充足的系统。
MS 为了下降和应用争抢 CPU 资源的现象发生,还提供了一种增量的模式,称为 i-CMS,在这种模式下,CMS 仅启动一个处理器线程来并发的扫描标记和清除,而且该线程在执行一小段时间后就会先将 CPU 使用权让出来,分屡次多段的方式来完成整个扫描标记和清除
的过程,这样下降了对于 CPU 资源的消耗,但同时也下降了 CMS 的性能,所以仅适用于 CPU少的应用。
CMS 为了减小产生的内存碎片,提升 jvm 空间的利用率,提供了一个整理碎片的功能,可经过在 jvm 中指定-XX:+ UseCMSCompactAtFullCollection (开启对内存空间的整理工做)来启动此功能,在启动了此功能后默认为每次 Full GC 的时候都会进行整理,也能够经过-XX:CMSFullGCsBeforeCompaction=来指定多少次 Full GC 后才执行整理,不过要注意的是,整理这个步骤是须要暂停整个应用的。
[--> 注 <--]
Mod Union Table ----在并发标记阶段Minor GC 形成的对象之间引用的变化
Card Table --- 在并发标记阶段应用程序自己形成对象之间引用的变化。