/* * Copyright (c) 2004, 2019, 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. * * This code is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * version 2 for more details (a copy is included in the LICENSE file that * accompanied this code). * * You should have received a copy of the GNU General Public License version * 2 along with this work; if not, write to the Free Software Foundation, * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA * or visit www.oracle.com if you need additional information or have any * questions. *
*/
// The throughput goal is implemented as // _throughput_goal = 1 - ( 1 / (1 + gc_cost_ratio)) // gc_cost_ratio is the ratio // application cost / gc cost // For example a gc_cost_ratio of 4 translates into a // throughput goal of .80
void AdaptiveSizePolicy::minor_collection_begin() { // Update the interval time
_minor_timer.stop(); // Save most recent collection time
_latest_minor_mutator_interval_seconds = _minor_timer.seconds();
_minor_timer.reset();
_minor_timer.start();
}
// The policy does not have enough data until at least some // young collections have been done.
_young_gen_policy_is_ready =
(_avg_minor_gc_cost->count() >= AdaptiveSizePolicyReadyThreshold);
// Calculate variables used to estimate pause time vs. gen sizes double eden_size_in_mbytes = ((double)_eden_size) / ((double)M);
update_minor_pause_young_estimator(minor_pause_in_ms);
update_minor_pause_old_estimator(minor_pause_in_ms);
log_trace(gc, ergo)("AdaptiveSizePolicy::minor_collection_end: minor gc cost: %f average: %f",
collection_cost, _avg_minor_gc_cost->average());
log_trace(gc, ergo)(" minor pause: %f minor period %f",
minor_pause_in_ms, _latest_minor_mutator_interval_seconds * MILLIUNITS);
// Calculate variable used to estimate collection cost vs. gen sizes
assert(collection_cost >= 0.0, "Expected to be non-negative");
_minor_collection_estimator->update(eden_size_in_mbytes, collection_cost);
}
// Interval times use this timer to measure the mutator time. // Reset the timer after the GC pause.
_minor_timer.reset();
_minor_timer.start();
}
// The decayed cost should always be smaller than the // average cost but the vagaries of finite arithmetic could // produce a larger value in decayed_major_gc_cost so protect // against that. return MIN2(major_gc_cost_average, decayed_major_gc_cost);
}
// Use a value of the major gc cost that has been decayed // by the factor // // average-interval-between-major-gc * AdaptiveSizeMajorGCDecayTimeScale / // time-since-last-major-gc // // if the average-interval-between-major-gc * AdaptiveSizeMajorGCDecayTimeScale // is less than time-since-last-major-gc. // // In cases where there are initial major gc's that // are of a relatively high cost but no later major // gc's, the total gc cost can remain high because // the major gc cost remains unchanged (since there are no major // gc's). In such a situation the value of the unchanging // major gc cost can keep the mutator throughput below // the goal when in fact the major gc cost is becoming diminishingly // small. Use the decaying gc cost only to decide whether to // adjust for throughput. Using it also to determine the adjustment // to be made for throughput also seems reasonable but there is // no test case to use to decide if it is the right thing to do // don't do it yet.
// Decay the major gc cost? if (time_since_last_major_gc >
((double) AdaptiveSizeMajorGCDecayTimeScale) * avg_major_interval) {
// Decay using the time-since-last-major-gc
decayed_major_gc_cost = decaying_major_gc_cost();
log_trace(gc, ergo)("decaying_gc_cost: major interval average: %f time since last major gc: %f",
avg_major_interval, time_since_last_major_gc);
log_trace(gc, ergo)(" major gc cost: %f decayed major gc cost: %f",
major_gc_cost(), decayed_major_gc_cost);
}
} double result = MIN2(1.0, decayed_major_gc_cost + minor_gc_cost()); return result;
}
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; constdouble free_limit_ratio = GCHeapFreeLimit / 100.0; constdouble mem_free_limit = total_mem * free_limit_ratio; constdouble mem_free_old_limit = _max_old_gen_size * free_limit_ratio; constdouble 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);
bool AdaptiveSizePolicy::print() const {
assert(UseAdaptiveSizePolicy, "UseAdaptiveSizePolicy need to be enabled.");
if (!log_is_enabled(Debug, gc, ergo)) { returnfalse;
}
// Print goal for which action is needed. char* action = NULL; bool change_for_pause = false; if ((change_old_gen_for_maj_pauses() ==
decrease_old_gen_for_maj_pauses_true) ||
(change_young_gen_for_min_pauses() ==
decrease_young_gen_for_min_pauses_true)) {
action = (char*) " *** pause time goal ***";
change_for_pause = true;
} elseif ((change_old_gen_for_throughput() ==
increase_old_gen_for_throughput_true) ||
(change_young_gen_for_throughput() ==
increase_young_gen_for_througput_true)) {
action = (char*) " *** throughput goal ***";
} elseif (decrease_for_footprint()) {
action = (char*) " *** reduced footprint ***";
} else { // No actions were taken. This can legitimately be the // situation if not enough data has been gathered to make // decisions. returnfalse;
}
// Pauses // Currently the size of the old gen is only adjusted to // change the major pause times. char* young_gen_action = NULL; char* tenured_gen_action = NULL;
// Throughput if (change_old_gen_for_throughput() == increase_old_gen_for_throughput_true) {
assert(change_young_gen_for_throughput() ==
increase_young_gen_for_througput_true, "Both generations should be growing");
young_gen_action = grow_msg;
tenured_gen_action = grow_msg;
} elseif (change_young_gen_for_throughput() ==
increase_young_gen_for_througput_true) { // Only the young generation may grow at start up (before // enough full collections have been done to grow the old generation).
young_gen_action = grow_msg;
tenured_gen_action = no_change_msg;
}
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.