CMS GC是Mostly Concurrent收集器,全称为Concurrent Mark Sweep GC,是一种以获取最短停顿时间为目标的收集器。CMS的设计初衷和目的是为了消除Parallel GC和Serial Old GC在Full GC时长时间的停顿,从名字(Mark Sweep)上就可以看出,CMS GC是基于标记-清除算法实现,这也导致服务长时间运行会有严重的内存碎片化问题。另外,算法在实现上也会比较复杂。
CMS GC从触发机制上可以分为Background Collector和Foregroud Collector(其实还有Mark-Sweep-Compact Collector,MSC Collector,也就是Java GC机制小结所示图片中,位于Serial Old下方的MSC,只是该算法基本可以认为就是Serial Old GC)。值的注意的是Foreground Collector已经在Java 9中被移除了。
Background Collector
Backgroud collector是通过CMS后台线程不断的去扫描,过程中主要是判断是否符合background collector的触发条件,一旦有符合的情况,就会进行一次background的collect。
void ConcurrentMarkSweepThread::run() {
... // 省略
while (!_should_terminate) {
sleepBeforeNextCycle();
if (_should_terminate) break;
GCCause::Cause cause = _collector->_full_gc_requested ?
_collector->_full_gc_cause : GCCause::_cms_concurrent_mark;
_collector->collect_in_background(false, cause);
}
... // 省略
}
每次扫描过程中,先等CMSWaitDuration(默认值是2s)时间,然后再去进行一次shouldConcurrentCollect判断,看是否满足CMS background collector的触发条件。
void ConcurrentMarkSweepThread::sleepBeforeNextCycle() {
while (!_should_terminate) {
if (CMSIncrementalMode) {
icms_wait();
if(CMSWaitDuration >= 0) {
// Wait until the next synchronous GC, a concurrent full gc
// request or a timeout, whichever is earlier.
wait_on_cms_lock_for_scavenge(CMSWaitDuration);
}
return;
} else {
if(CMSWaitDuration >= 0) {
// Wait until the next synchronous GC, a concurrent full gc
// request or a timeout, whichever is earlier.
wait_on_cms_lock_for_scavenge(CMSWaitDuration);
} else {
// Wait until any cms_lock event or check interval not to call shouldConcurrentCollect permanently
wait_on_cms_lock(CMSCheckInterval);
}
}
// Check if we should start a CMS collection cycle
if (_collector->shouldConcurrentCollect()) {
return;
}
// .. collection criterion not yet met, let's go back
// and wait some more
}
}
让我们来看看shouldConcurrentCollect方法中有哪些条件呢?
bool CMSCollector::shouldConcurrentCollect() {
// 第一种触发情况,是否并行Full GC
if (_full_gc_requested) {
if (Verbose && PrintGCDetails) {
gclog_or_tty->print_cr("CMSCollector: collect because of explicit "
" gc request (or gc_locker)");
}
return true;
}
// For debugging purposes, change the type of collection.
// If the rotation is not on the concurrent collection
// type, don't start a concurrent collection.
NOT_PRODUCT(
if (RotateCMSCollectionTypes &&
(_cmsGen->debug_collection_type() !=
ConcurrentMarkSweepGeneration::Concurrent_collection_type)) {
assert(_cmsGen->debug_collection_type() !=
ConcurrentMarkSweepGeneration::Unknown_collection_type,
"Bad cms collection type");
return false;
}
)
FreelistLocker x(this);
// ------------------------------------------------------------------
// Print out lots of information which affects the initiation of
// a collection.
if (PrintCMSInitiationStatistics && stats().valid()) {
gclog_or_tty->print("CMSCollector shouldConcurrentCollect: ");
gclog_or_tty->stamp();
gclog_or_tty->cr();
stats().print_on(gclog_or_tty);
gclog_or_tty->print_cr("time_until_cms_gen_full %3.7f",
stats().time_until_cms_gen_full());
gclog_or_tty->print_cr("free=" SIZE_FORMAT, _cmsGen->free());
gclog_or_tty->print_cr("contiguous_available=" SIZE_FORMAT,
_cmsGen->contiguous_available());
gclog_or_tty->print_cr("promotion_rate=%g", stats().promotion_rate());
gclog_or_tty-&