cms java gc_深入理解CMS GC

concurrent mode failure

1. 在cms并发周期执行期间,用户的线程依然在运行,如果这时候如果应用线程向老年代请求分配的空间超过预留的空间,就会抛出该错误 - 后台线程的收集没有赶上应用线程的分配速度

2. 有时候“空间不足”是CMS GC时当前的浮动垃圾过多导致暂时性的空间不足,而浮动垃圾就是cms执行期间用户线程申请的内存空间

3. 这个错误可能触发两种情况

> cms的foreground模式(默认的cms gc属于background模式),这个模式是CMS自己的mark-sweep来做不并发的(串行的)old generation GC,不过会将一些阶段省略掉。

+ CMS的foreground collector的算法就是普通的mark-sweep。它收集的范围只是CMS的old generation,而不包括其它generation。因而它在HotSpot VM里不叫做full GC

> Serial Old GC

+ mark-sweep-compact算法

+ 它收集的范围是整个GC堆,包括Java heap的young generation和old generation,以及non-Java heap的permanent generation。因而其名 Full GC

> 前者的出现原因:A STW foreground collection can pick up where a concurrent background collection left off to try to avoid a full GC. This is nice but normally it has worse performance than a full GC.

+ 即是为了避免fgc,但是往往性能甚至比fgc更差

> 对于第一种foreground模式,必须要 -XX:-UseCMSCompactAtFullCollection & -XX:CMSFullGCsBeforeCompaction设置大于0

+ 但是UseCMSCompactAtFullCollection默认为true,CMSFullGCsBeforeCompaction默认是0,所以一定会触发第二种Serial Old GC

> 参考:

+ https://bugs.openjdk.java.net/browse/JDK-8010202

+ https://bugs.openjdk.java.net/browse/JDK-8064702

+ https://bugs.openjdk.java.net/browse/JDK-8027132

+ 均建议foreground collector在Java8废弃,在Java9移除,包括UseCMSCompactAtFullCollection和CMSFullGCsBeforeCompaction这两个参数

4. 所以通常来说不建议设置上面两个参数,否则可能在Java8中会触发foreground collector,可能会更慢(单线程)。所以通常当出现concurrent mode failure时触发的都是Serial Old GC

1. 关于UseCMSCompactAtFullCollection和CMSFullGCsBeforeCompaction的警告源代码

runtime\arguments.cpp

if (FLAG_IS_CMDLINE(UseCMSCompactAtFullCollection)) {

warning("UseCMSCompactAtFullCollection is deprecated and will likely be removed in a future release.");

}

if (FLAG_IS_CMDLINE(CMSFullGCsBeforeCompaction)) {

warning("CMSFullGCsBeforeCompaction is deprecated and will likely be removed in a future release.");

}

2. 关于用哪种处理方式的源代码 gc_implementation/concurrentMarkSweep/concurrentMarkSweepGeneration.cpp

void CMSCollector::acquire_control_and_collect{

...

bool should_compact = false;

decide_foreground_collection_type(clear_all_soft_refs,

&should_compact, &should_start_over);

...

if (should_compact) {

...

// 这个就是mark-sweep-compact 的 Full GC

do_compaction_work(clear_all_soft_refs);

...

}else {

// mark-sweep

do_mark_sweep_work(clear_all_soft_refs, first_state,

should_start_over);

}

*should_compact =

UseCMSCompactAtFullCollection &&

((_full_gcs_since_conc_gc >= CMSFullGCsBeforeCompaction) ||

GCCause::is_user_requested_gc(gch->gc_cause()) ||

gch->incremental_collection_will_fail(true /* consult_young */));

而should_compact主要的一个判断逻辑就是判断UseCMSCompactAtFullCollection和CMSFullGCsBeforeCompaction这两个参数

promotion failed

1. Java Performance,The Definitive Guide的原文是这样描述的:

- Here, CMS started a young collection and assumed that there was enough free space to hold all the promoted objects (otherwise, it would have declared a concurrent mode failure). That assumption proved incorrect: CMS couldn’t promote the objects because the old generation was fragmented (or, much less likely, because the amount of memory to be promoted was bigger than CMS expected).

- 翻译:新生代垃圾收集,判断老年代似乎有足够的空闲空间可以容纳所有的晋升对象(否则,CMS收集器会报concurrent mode failure)。这个假设最终被证明是错误的,由于老年代空间的碎片化(或者,不太贴切的说,由于晋升实际要占用的内存超过了CMS收集器的判断),CMS收集器无法晋升这些对象。

2. Sometimes we see these promotion failures even when thelogs show that there is enough free space in tenured generation. The reason is'fragmentation' - the free space available in tenured generation is notcontiguous, and promotions from young generation require a contiguous freeblock to be available in tenured generation. CMS collector is a non-compactingcollector, so can cause fragmentation of space for some type of applications.

- 翻译:CMS收集器对老年代收集的时候,不再进行任何压缩和整理的工作,意味着老年代随着应用的运行会变得碎片化;碎片过多会影响大对象的分配,虽然老年代还有很大的剩余空间,但是没有连续的空间来分配大对象

3. 如果在ParNew准备收集时CMS说晋升没问题,但ParNew已经开始收集之后确实遇到了晋升失败的情况

4. promotion failed是说,担保机制确定老年代是否有足够的空间容纳新来的对象,如果担保机制说有,但是真正分配的时候发现由于碎片导致找不到连续的空间而失败;而concurrent mode failure是指并发周期还没执行完,用户线程就来请求比预留空间更大的空间了,即后台线程的收集没有赶上应用线程的分配速度。

5. promotion failed触发fgc,触发模式同上,通常也是Serial Old GC

permgen (or the metaspace) fills up

1. 对于Java8来说,这个主要是在metaspace扩容时触发的

2. 如果老年代设置了 CMS,则 Metasapce 扩容引起的 FGC 会转变成一次 CMS

3. Java8中收集器默认就会收集元空间中不再载入的类

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值