一个 JVM 参数引发的频繁 CMS GC( 四 )


Young GC 后 eden、from、to 三个 space 的使用量都不是 0 的情况 , 而且 OldGen 空闲空间很大 , 为什么 Young GC 好像没起作用 。
源码排查OldGen 的使用占比情况都没有达到 80% , 什么原因导致的 CMS GC下面我们来看下 CMS GC 触发条件 , 触发条件都在 shouldConcurrentCollect 函数里 , 返回 true 的都是可能的情况 , 这里分别解释下 。

  • “if (fullgc_requested)”这是由 System.gc() 调用且配置了 -XX:+ExplicitGCInvokesConcurrent 参数的情况下 , 会触发一次 CMS GC 。 但如果是 System.gc() , 每次 CMS GC 的间隔时间不可能一直是 2s , 故显然不符合 。
  • “if (!UseCMSInitiatingOccupancyOnly)”这是在没有配置 -XX:+UseCMSInitiatingOccupancyOnly 参数的情况下 , 可能触发 CMS GC 的情况 , 故显然不符合 。
  • “if (cmsGen->shouldconcurrent_collect())”这是 -XX:+UseCMSInitiatingOccupancyOnly 参数的情况下 , 如果 OldGen 使用占比达到 -XX:CMSInitiatingOccupancyFraction 参数设置值 , 就会触发 CMS GC , 但第二次、第三-第 N 次明显不符合情况 。
  • “if (gch->incrementalcollectionwillfail(true /* consultyoung */))”这是一种悲观策略 , 判断新生代回收是否会失败 , 如果最近一次 Young GC 已经失败或者可能会失败 , 就会触发一次 CMS GC 。 这是符合本文说的情况的 。
  • “if (MetaspaceGC::shouldconcurrentcollect())”这是 Metaspace 满足 CMS GC 触发条件的情况 , 根据日志 “ Metaspace used 90199K, capacity 91456K, committed 91776K, reserved 1130496K” 中 Metaspace 空间使用情况 , 显然不符合 。
  • “if (CMSTriggerInterval >= 0)”这是配置了 -XX:CMSTriggerInterval 参数的情况 , 显然不符合 。
bool CMSCollector::shouldConcurrentCollect() {LogTarget(Trace, gc) log;if (_full_gc_requested) {log.print("CMSCollector: collect because of explicitgc request (or GCLocker)");return true;}FreelistLocker x(this);// ------------------------------------------------------------------// Print out lots of information which affects the initiation of// a collection.if (log.is_enabled()LogStream out(log);stats().print_on(log.print("time_until_cms_gen_full %3.7f", stats().time_until_cms_gen_full());log.print("free=" SIZE_FORMAT, _cmsGen->free());log.print("contiguous_available=" SIZE_FORMAT, _cmsGen->contiguous_available());log.print("promotion_rate=%g", stats().promotion_rate());log.print("cms_allocation_rate=%g", stats().cms_allocation_rate());log.print("occupancy=%3.7f", _cmsGen->occupancy());log.print("initiatingOccupancy=%3.7f", _cmsGen->initiating_occupancy());log.print("cms_time_since_begin=%3.7f", stats().cms_time_since_begin());log.print("cms_time_since_end=%3.7f", stats().cms_time_since_end());log.print("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) {log.print(" 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 THISif (_cmsGen->should_concurrent_collect()) {log.print("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_generation_policy(),"You may want to check the correctness of the following");if (gch->incremental_collection_will_fail(true /* consult_young */)) {log.print("CMSCollector: collect because incremental collection will fail ");return true;}if (MetaspaceGC::should_concurrent_collect()) {log.print("CMSCollector: collect for metadata allocation ");return true;}// CMSTriggerInterval starts a CMS cycle if enough time has passed.if (CMSTriggerInterval >= 0) {if (CMSTriggerInterval == 0) {// Trigger alwaysreturn true;}// Check the CMS time since begin (we do not check the stats validity// as we want to be able to trigger the first CMS cycle as well)if (stats().cms_time_since_begin() >= (CMSTriggerInterval / ((double) MILLIUNITS))) {if (stats().valid()) {log.print("CMSCollector: collect because of trigger interval (time since last begin %3.7f secs)",stats().cms_time_since_begin());} else {log.print("CMSCollector: collect because of trigger interval (first collection)");}return true;}}return false;}


推荐阅读