| 副标题[/!--empirenews.page--] 经常有同学会问,为啥我的应用 Old Gen 的使用占比没达到 CMSInitiatingOccupancyFraction 参数配置的阈值,就触发了  CMS GC,表示很莫名奇妙,不知道问题出在哪? 
 其实 CMS GC 的触发条件非常多,不只是 CMSInitiatingOccupancyFraction 阈值触发这么简单。本文通过源码全面梳理了触发  CMS GC 的条件,尽可能的帮你了解平时遇到的奇奇怪怪的 CMS GC 问题。 先抛出一些问题,来吸引你的注意力。 
    为什么 Old Gen 使用占比仅 50% 就进行了一次 CMS GC?Metaspace 的使用也会触发 CMS GC 吗?为什么 Old Gen  使用占比非常小就进行了一次 CMS GC? 触发条件 CMS GC 在实现上分成 foreground collector 和 background collector。foreground  collector 相对比较简单,background collector 比较复杂,情况比较多。 下面我们从 foreground collector 和 background collector 分别来说明他们的触发条件: 说明:本文内容是基于 JDK 8 说明:本文仅涉及 CMS GC 的触发条件,至于算法的具体过程,以及什么时候进行 MSC(mark sweep  compact)不在本文范围 foreground collector foreground collector 触发条件比较简单,一般是遇到对象分配但空间不够,就会直接触发 GC,来立即进行空间回收。采用的算法是 mark  sweep,不压缩。 background collector 说明 background collector 的触发条件之前,先来说下 background 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 时间,然后再去进行一次 shouldConcurrentCollect 判断,看是否满足 CMS  background collector 的触发条件。CMSWaitDuration 默认时间是 2s(经常会有业务遇到频繁的 CMS GC,注意看每次 CMS  GC 之间的时间间隔,如果是 2s,那基本就可以断定是 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() { // 第一种触发情况 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->print_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->print_cr("cms_allocation_rate=%g", stats().cms_allocation_rate()); gclog_or_tty->print_cr("occupancy=%3.7f", _cmsGen->occupancy()); gclog_or_tty->print_cr("initiatingOccupancy=%3.7f", _cmsGen->initiating_occupancy()); gclog_or_tty->print_cr("metadata initialized %d", MetaspaceGC::should_concurrent_collect()); } // ------------------------------------------------------------------ // 第二种触发情况 // If the estimated time to complete a cms collection (cms_duration()) // is less than the estimated time remaining until the cms generation // is full, start a collection. if (!UseCMSInitiatingOccupancyOnly) { if (stats().valid()) { if (stats().time_until_cms_start() == 0.0) { return true; } } else { // We want to conservatively collect somewhat early in order // to try and "bootstrap" our CMS/promotion statistics; // this branch will not fire after the first successful CMS // collection because the stats should then be valid. if (_cmsGen->occupancy() >= _bootstrap_occupancy) { if (Verbose && PrintGCDetails) { gclog_or_tty->print_cr( " CMSCollector: collect for bootstrapping statistics:" " occupancy = %f, boot occupancy = %f", _cmsGen->occupancy(), _bootstrap_occupancy); } return true; } } } // 第三种触发情况 // Otherwise, we start a collection cycle if // old gen want a collection cycle started. Each may use // an appropriate criterion for making this decision. // XXX We need to make sure that the gen expansion // criterion dovetails well with this. XXX NEED TO FIX THIS if (_cmsGen->should_concurrent_collect()) { if (Verbose && PrintGCDetails) { gclog_or_tty->print_cr("CMS old gen initiated"); } return true; } // 第四种触发情况 // We start a collection if we believe an incremental collection may fail; // this is not likely to be productive in practice because it's probably too // late anyway. GenCollectedHeap* gch = GenCollectedHeap::heap(); assert(gch->collector_policy()->is_two_generation_policy(), "You may want to check the correctness of the following"); if (gch->incremental_collection_will_fail(true /* consult_young */)) { if (Verbose && PrintGCDetails) { gclog_or_tty->print("CMSCollector: collect because incremental collection will fail "); } return true; } // 第五种触发情况 if (MetaspaceGC::should_concurrent_collect()) { if (Verbose && PrintGCDetails) { gclog_or_tty->print("CMSCollector: collect for metadata allocation "); } return true; } return false; } 
 上述代码可知,从大类上分, background collector 一共有 5 种触发情况: 1.是否是并行 Full GC (编辑:南平站长网) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |