void AdaptiveSizePolicy::check_gc_overhead_limit( size_t young_live, size_t eden_live, size_t max_old_gen_size, size_t max_eden_size, bool is_full_gc, GCCause::Cause gc_cause, CollectorPolicy* collector_policy) { // Ignore explicit GC's. Exiting here does not set the flag and // does not reset the count. Updating of the averages for system // GC's is still controlled by UseAdaptiveSizePolicyWithSystemGC. if (GCCause::is_user_requested_gc(gc_cause) || GCCause::is_serviceability_requested_gc(gc_cause)) { return; } // eden_limit is the upper limit on the size of eden based on // the maximum size of the young generation and the sizes // of the survivor space. // The question being asked is whether the gc costs are high // and the space being recovered by a collection is low. // free_in_young_gen is the free space in the young generation // after a collection and promo_live is the free space in the old // generation after a collection. // // Use the minimum of the current value of the live in the // young gen or the average of the live in the young gen. // If the current value drops quickly, that should be taken // into account (i.e., don't trigger if the amount of free // space has suddenly jumped up). If the current is much // higher than the average, use the average since it represents // the longer term behavor. const size_t live_in_eden = MIN2(eden_live, (size_t) avg_eden_live()->average()); const size_t free_in_eden = max_eden_size > live_in_eden ? max_eden_size - live_in_eden : 0; const size_t free_in_old_gen = (size_t)(max_old_gen_size - avg_old_live()->average()); const size_t total_free_limit = free_in_old_gen + free_in_eden; const size_t total_mem = max_old_gen_size + max_eden_size; const double mem_free_limit = total_mem * (GCHeapFreeLimit/100.0); const double mem_free_old_limit = max_old_gen_size * (GCHeapFreeLimit/100.0); const double mem_free_eden_limit = max_eden_size * (GCHeapFreeLimit/100.0); const double gc_cost_limit = GCTimeLimit/100.0; size_t promo_limit = (size_t)(max_old_gen_size - avg_old_live()->average()); // But don't force a promo size below the current promo size. Otherwise, // the promo size will shrink for no good reason. promo_limit = MAX2(promo_limit, _promo_size); if (PrintAdaptiveSizePolicy && (Verbose || (free_in_old_gen < (size_t) mem_free_old_limit && free_in_eden < (size_t) mem_free_eden_limit))) { gclog_or_tty->print_cr( "PSAdaptiveSizePolicy::compute_generation_free_space limits:" " promo_limit: " SIZE_FORMAT " max_eden_size: " SIZE_FORMAT " total_free_limit: " SIZE_FORMAT " max_old_gen_size: " SIZE_FORMAT " max_eden_size: " SIZE_FORMAT " mem_free_limit: " SIZE_FORMAT, promo_limit, max_eden_size, total_free_limit, max_old_gen_size, max_eden_size, (size_t) mem_free_limit); } bool print_gc_overhead_limit_would_be_exceeded = false; if (is_full_gc) { if (gc_cost() > gc_cost_limit && free_in_old_gen < (size_t) mem_free_old_limit && free_in_eden < (size_t) mem_free_eden_limit) { // Collections, on average, are taking too much time, and // gc_cost() > gc_cost_limit // we have too little space available after a full gc. // total_free_limit < mem_free_limit // where // total_free_limit is the free space available in // both generations // total_mem is the total space available for allocation // in both generations (survivor spaces are not included // just as they are not included in eden_limit). // mem_free_limit is a fraction of total_mem judged to be an // acceptable amount that is still unused. // The heap can ask for the value of this variable when deciding // whether to thrown an OutOfMemory error. // Note that the gc time limit test only works for the collections // of the young gen + tenured gen and not for collections of the // permanent gen. That is because the calculation of the space // freed by the collection is the free space in the young gen + // tenured gen. // At this point the GC overhead limit is being exceeded. inc_gc_overhead_limit_count(); if (UseGCOverheadLimit) { if (gc_overhead_limit_count() >= AdaptiveSizePolicyGCTimeLimitThreshold){ // All conditions have been met for throwing an out-of-memory set_gc_overhead_limit_exceeded(true); // Avoid consecutive OOM due to the gc time limit by resetting // the counter. reset_gc_overhead_limit_count(); } else { // The required consecutive collections which exceed the // GC time limit may or may not have been reached. We // are approaching that condition and so as not to // throw an out-of-memory before all SoftRef's have been // cleared, set _should_clear_all_soft_refs in CollectorPolicy. // The clearing will be done on the next GC. bool near_limit = gc_overhead_limit_near(); if (near_limit) { collector_policy->set_should_clear_all_soft_refs(true); if (PrintGCDetails && Verbose) { gclog_or_tty->print_cr(" Nearing GC overhead limit, " "will be clearing all SoftReference"); } } } } // Set this even when the overhead limit will not // cause an out-of-memory. Diagnostic message indicating // that the overhead limit is being exceeded is sometimes // printed. print_gc_overhead_limit_would_be_exceeded = true; } else { // Did not exceed overhead limits reset_gc_overhead_limit_count(); } } if (UseGCOverheadLimit && PrintGCDetails && Verbose) { if (gc_overhead_limit_exceeded()) { gclog_or_tty->print_cr(" GC is exceeding overhead limit " "of %d%%", GCTimeLimit); reset_gc_overhead_limit_count(); } else if (print_gc_overhead_limit_would_be_exceeded) { assert(gc_overhead_limit_count() > 0, "Should not be printing"); gclog_or_tty->print_cr(" GC would exceed overhead limit " "of %d%% %d consecutive time(s)", GCTimeLimit, gc_overhead_limit_count()); } } }
// Tests conditions indicate the GC overhead limit is being approached. bool gc_overhead_limit_near() { return gc_overhead_limit_count() >= (AdaptiveSizePolicyGCTimeLimitThreshold - 1); }