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

接下来 , 我们具体分析下 incrementalcollectionwillfail(true) 函数 , 这个函数有两个判断条件 incrementalcollectionfailed() 或者 !younggen->collectionattemptissafe() , 有一个成立就会返回 true 。
// Returns true if an incremental collection is likely to fail.// We optionally consult the young gen, if asked to do so;// otherwise we base our answer on whether the previous incremental// collection attempt failed with no corrective action as of yet.bool incremental_collection_will_fail(bool consult_young) {// The first disjunct remembers if an incremental collection failed, even// when we thought (second disjunct) that it would not.return incremental_collection_failed() ||(consult_young}bool incremental_collection_failed() const {return _incremental_collection_failed;}我们先来看 incrementalcollectionfailed() 函数 , 这个函数返回的是incrementalcollectionfailed 这个成员的值 , 这个值只有两个情况下会通过 setincrementalcollectionfailed() 函数设置成 true , 并且会在 CMS GC 的 sweep 阶段会设置为 false 。 第一种情况是:晋升失败 Promotion failed , 但是只有第一次 CMS GC 出现过一次 , 后续的Young GC 都不是 promotion failed , 说明不是这种情况 。
void ParNewGeneration::handle_promotion_failed(GenCollectedHeap* gch, ParScanThreadStateSet_promo_failure_scan_stack.clear(true); // Clear cached segments.remove_forwarding_pointers();log_info(gc, promotion)("Promotion failed");// All the spaces are in play for mark-sweep.swap_spaces();// Make life simpler for CMS || rescan; see 6483690.from()->set_next_compaction_space(to());gch->set_incremental_collection_failed();// Inform the next generation that a promotion failure occurred._old_gen->promotion_failure_occurred();// Trace promotion failure in the parallel GC threadsthread_state_set.trace_promotion_failed(gc_tracer());// Single threaded code may have reported promotion failure to the global stateif (_promotion_failed_info.has_failed()) {_gc_tracer.report_promotion_failed(_promotion_failed_info);}// Reset the PromotionFailureALot counters.NOT_PRODUCT(gch->reset_promotion_should_fail();)}第二种情况是:Young GC 过程中 , if (!collectionattemptissafe()) 为 true , 也会通过 setincrementalcollectionfailed() 函数设置 。
void ParNewGeneration::collect(boolfull,boolclear_all_soft_refs,size_t size,boolis_tlab) {assert(full || size > 0, "otherwise we don't want to collect");GenCollectedHeap* gch = GenCollectedHeap::heap();_gc_timer->register_gc_start();AdaptiveSizePolicy* size_policy = gch->gen_policy()->size_policy();WorkGang* workers = gch->workers();assert(workers != NULL, "Need workgang for parallel work");uint active_workers =AdaptiveSizePolicy::calc_active_workers(workers->total_workers(),workers->active_workers(),Threads::number_of_non_daemon_threads());active_workers = workers->update_active_workers(active_workers);log_info(gc,task)("Using %u workers of %u for evacuation", active_workers, workers->total_workers());_old_gen = gch->old_gen();// If the next generation is too full to accommodate worst-case promotion// from this generation, pass on collection; let the next generation// do it.if (!collection_attempt_is_safe()) {gch->set_incremental_collection_failed();// slight lie, in that we did not even attempt onereturn;}


推荐阅读