From db552403d2f204efbc3b9c81b57fe4d8792f6558 Mon Sep 17 00:00:00 2001 From: asahi Date: Tue, 2 Dec 2025 23:23:19 +0800 Subject: [PATCH] =?UTF-8?q?doc:=20=E9=98=85=E8=AF=BBcms=E6=96=87=E6=A1=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- jvm/深入理解java虚拟机.md | 31 +++++++++++++++++++++++++++++++ 1 file changed, 31 insertions(+) diff --git a/jvm/深入理解java虚拟机.md b/jvm/深入理解java虚拟机.md index 6e55e76..46f553a 100644 --- a/jvm/深入理解java虚拟机.md +++ b/jvm/深入理解java虚拟机.md @@ -47,6 +47,8 @@ - [GCTimeRatio](#gctimeratio) - [Serial Old](#serial-old) - [Parallel Old](#parallel-old) + - [CMS收集器](#cms收集器) + - [CMS缺陷](#cms缺陷) # 深入理解java虚拟机 @@ -389,4 +391,33 @@ Parallel Old主要是和Parallel Scavenge搭配使用,否则Parallel Scavenge > 在Parallel Scavenge/Parallel Old搭配使用时,发生GC时用户线程也都处于暂停状态。 +#### CMS收集器 +CMS(Concurrent Mark Sweep)是一种`以获取最短回收停顿时间`的收集器。在重视服务响应时间的应用中,适合使用CMS收集器进行老年代的垃圾回收。 + +从名字上可以看出,CMS收集器基于`标记-清除`算法实现,其运作过程相对于前面集中收集器来说更加复杂,其分为如下步骤: +- 初始标记(STW): + - 初始标记仅仅会标记GC Roots能够直接关联到的对象,速度很快 +- 并发标记: + - 并发标记阶段会执行GC Roots Tracing +- 重新标记(STW) + - 重新标记期间会修正并发标记期间因用户线程继续运作而导致标记产生变动的那一部分对象的标记记录 + - 该阶段的耗时比初始标记长,但是远比并发标记短 +- 并发清除 + +在CMS的整个收集过程中,初始标记和重新标记阶段是存在STW的,但是并发标记和并发清除时收集器线程可以和用户线程同时运行。 + + + +##### CMS缺陷 +CMS虽然在垃圾收集时能够做到停顿时间较短,但是其仍然存在如下缺陷: +- CMS对CPU资源比较敏感。`CMS默认启动的回收线程数是(CPU数量 + 3)/4个,当cpu物理核心数较少时,垃圾收集线程将会抢占大量cpu资源` +- CMS无法处理浮动垃圾,由于CMS在并发清理阶段并不会引入STW,故而此时用户进程可以运行并伴随新的垃圾产生。该部分垃圾cms无法进行处理,只能等待下一次GC来清掉。 + - 由于在并发清除阶段同时还有用户线程运行,必须为用户线程预留内存,`故而CMS无法在老年代空间几乎被填满后才进行垃圾收集`,`需预留一部分空间以供并发收集时用户线程使用` + - 在JDK 1.6中,CMS收集器的启动阈值提升到了92%,要是预留的内存没有办法满足用户线程的运行需要,`会出现Concurrent Mode Failure`,此时虚拟机将执行后备方案`临时启用Serial Old收集器重新进行老年代的垃圾收集` + - 故而`-XX:CMSInitiatingOccupancyFraction`参数设置过大时,容易产生大量`Concurrent Mode Failure`,性能反而降低 +- CMS是一款基于标记-清除算法的老年代垃圾收集器,故而在收集结束时会有大量的内存碎片产生 + - 为了解决内存碎片问题,CMS提供了`-XX:+UseCMSCompactAtFullCollection`开关参数(默认是开启的),用于在CMS进行full gc时开启内存碎片的合并过程 + - 但是,每次full gc都进行内存碎片合并会导致等待时间过长,故而引入了另一个参数`-XX:CMSFullGCsBeforeCompaction`,该参数用于限制执行多少次不压缩的full gc后,再执行一次带压缩的(默认为0,代表每次进入fullgc后都进行碎片整理) + +