< prev index next >
src/hotspot/share/gc/shared/adaptiveSizePolicy.cpp
Print this page
rev 52582 : 8212206: Refactor AdaptiveSizePolicy to separate out code related to GC overhead
Summary: Move check_gc_overhead_limit() and related code to its own class
Reviewed-by:
*** 1,7 ****
/*
! * Copyright (c) 2004, 2016, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
--- 1,7 ----
/*
! * Copyright (c) 2004, 2018, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*** 25,35 ****
#include "precompiled.hpp"
#include "gc/shared/adaptiveSizePolicy.hpp"
#include "gc/shared/collectorPolicy.hpp"
#include "gc/shared/gcCause.hpp"
#include "gc/shared/gcUtil.inline.hpp"
- #include "gc/shared/softRefPolicy.hpp"
#include "gc/shared/workgroup.hpp"
#include "logging/log.hpp"
#include "runtime/timer.hpp"
#include "utilities/ostream.hpp"
--- 25,34 ----
*** 51,63 ****
uint gc_cost_ratio) :
_throughput_goal(1.0 - double(1.0 / (1.0 + (double) gc_cost_ratio))),
_eden_size(init_eden_size),
_promo_size(init_promo_size),
_survivor_size(init_survivor_size),
- _gc_overhead_limit_exceeded(false),
- _print_gc_overhead_limit_would_be_exceeded(false),
- _gc_overhead_limit_count(0),
_latest_minor_mutator_interval_seconds(0),
_threshold_tolerance_percent(1.0 + ThresholdTolerance/100.0),
_gc_pause_goal_sec(gc_pause_goal_sec),
_young_gen_change_for_minor_throughput(0),
_old_gen_change_for_major_throughput(0) {
--- 50,59 ----
*** 402,542 ****
set_change_young_gen_for_throughput(0);
set_decrease_for_footprint(0);
set_decide_at_full_gc(0);
}
! 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,
! SoftRefPolicy* soft_ref_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 behavior.
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);
-
log_trace(gc, ergo)(
! "PSAdaptiveSizePolicy::check_gc_overhead_limit:"
" 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) {
! soft_ref_policy->set_should_clear_all_soft_refs(true);
! log_trace(gc, ergo)("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) {
! if (gc_overhead_limit_exceeded()) {
! log_trace(gc, ergo)("GC is exceeding overhead limit of " UINTX_FORMAT "%%", 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");
! log_trace(gc, ergo)("GC would exceed overhead limit of " UINTX_FORMAT "%% %d consecutive time(s)",
! GCTimeLimit, gc_overhead_limit_count());
! }
! }
}
// Printing
bool AdaptiveSizePolicy::print() const {
assert(UseAdaptiveSizePolicy, "UseAdaptiveSizePolicy need to be enabled.");
--- 398,516 ----
set_change_young_gen_for_throughput(0);
set_decrease_for_footprint(0);
set_decide_at_full_gc(0);
}
! class AdaptiveSizePolicyTimeOverheadTester: public OverheadTester {
! double _gc_cost;
!
! public:
! AdaptiveSizePolicyTimeOverheadTester(double gc_cost) : _gc_cost(gc_cost) {}
!
! bool is_exceeded() {
! // 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.
! return _gc_cost > (GCTimeLimit / 100.0);
! }
! };
!
! class AdaptiveSizePolicySpaceOverheadTester: public OverheadTester {
! size_t _eden_live;
! size_t _max_old_gen_size;
! size_t _max_eden_size;
! size_t _promo_size;
! double _avg_eden_live;
! double _avg_old_live;
!
! public:
! AdaptiveSizePolicySpaceOverheadTester(size_t eden_live,
size_t max_old_gen_size,
size_t max_eden_size,
! size_t promo_size,
! double avg_eden_live,
! double avg_old_live) :
! _eden_live(eden_live),
! _max_old_gen_size(max_old_gen_size),
! _max_eden_size(max_eden_size),
! _promo_size(promo_size),
! _avg_eden_live(avg_eden_live),
! _avg_old_live(avg_old_live) {}
! bool is_exceeded() {
! // _max_eden_size 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 space being recovered by
! // a collection is low.
! // free_in_eden is the free space in eden after a collection and
! // free_in_old_gen is the free space in the old generation after
! // a collection.
//
! // Use the minimum of the current value of the live in eden
! // or the average of the live in eden.
// 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 behavior.
const size_t live_in_eden =
! MIN2(_eden_live, (size_t)_avg_eden_live);
! 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);
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 free_limit_ratio = GCHeapFreeLimit / 100.0;
! const double mem_free_limit = total_mem * free_limit_ratio;
! const double mem_free_old_limit = _max_old_gen_size * free_limit_ratio;
! const double mem_free_eden_limit = _max_eden_size * free_limit_ratio;
! size_t promo_limit = (size_t)(_max_old_gen_size - _avg_old_live);
// 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);
log_trace(gc, ergo)(
! "AdaptiveSizePolicySpaceOverheadTester::is_exceeded:"
" 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);
! return free_in_old_gen < (size_t)mem_free_old_limit &&
! free_in_eden < (size_t)mem_free_eden_limit;
}
! };
!
! void AdaptiveSizePolicy::check_gc_overhead_limit(
! size_t eden_live,
! size_t max_old_gen_size,
! size_t max_eden_size,
! bool is_full_gc,
! GCCause::Cause gc_cause,
! SoftRefPolicy* soft_ref_policy) {
!
! AdaptiveSizePolicyTimeOverheadTester time_overhead(gc_cost());
! AdaptiveSizePolicySpaceOverheadTester space_overhead(eden_live,
! max_old_gen_size,
! max_eden_size,
! _promo_size,
! avg_eden_live()->average(),
! avg_old_live()->average());
! _overhead_checker.check_gc_overhead_limit(&time_overhead,
! &space_overhead,
! is_full_gc,
! gc_cause,
! soft_ref_policy);
}
// Printing
bool AdaptiveSizePolicy::print() const {
assert(UseAdaptiveSizePolicy, "UseAdaptiveSizePolicy need to be enabled.");
< prev index next >