一、[ParNew (promotion failed): ...
这种情况就是单纯出现了promotion failed,此时cms未执行并发收集
二、concurrent mode failure): ...
这种情况是单纯的cms正在执行并发收集,然后用户线程申请内存空间不足
三、 [ParNew (promotion failed): ... (concurrent mode failure):...
这种情况是先出现了promotion failed,然后准备触发fgc
而此时cms这在执行并发收集,此时则执行打断逻辑,输出concurrent mode failure
具体源代码也是concurrentMarkSweepGeneration.cpp
四、promotion failed
- 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收集器无法晋升这些对象。
 
 - 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收集器对老年代收集的时候,不再进行任何压缩和整理的工作,意味着老年代随着应用的运行会变得碎片化;碎片过多会影响大对象的分配,虽然老年代还有很大的剩余空间,但是没有连续的空间来分配大对象
 
 - 如果在ParNew准备收集时CMS说晋升没问题,但ParNew已经开始收集之后确实遇到了晋升失败的情况
 - promotion failed是说,担保机制确定老年代是否有足够的空间容纳新来的对象,如果担保机制说有,但是真正分配的时候发现由于碎片导致找不到连续的空间而失败;而concurrent mode failure是指并发周期还没执行完,用户线程就来请求比预留空间更大的空间了,即后台线程的收集没有赶上应用线程的分配速度。
 - promotion failed触发fgc,触发模式同上,通常也是Serial Old GC
 
五、并发模式失败(Concurrent mode failure)
- 在cms并发周期执行期间,用户的线程依然在运行,如果这时候如果应用线程向老年代请求分配的空间超过预留的空间,就会抛出该错误 - 后台线程的收集没有赶上应用线程的分配速度
 - 有时候“空间不足”是CMS GC时当前的浮动垃圾过多导致暂时性的空间不足,而浮动垃圾就是cms执行期间用户线程申请的内存空间
 - 这个错误可能触发两种情况
 
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
+ 均建议foreground collector在Java8废弃,在Java9移除,包括UseCMSCompactAtFullCollection和CMSFullGCsBeforeCompaction这两个参数
- 所以通常来说不建议设置上面两个参数,否则可能在Java8中会触发foreground collector,可能会更慢(单线程)。所以通常当出现concurrent mode failure时触发的都是Serial Old GC
 












网友评论