6974966: G1: unnecessary direct-to-old allocations

This change revamps the slow allocation path of G1. Improvements include the following: a) Allocations directly to old regions are now totally banned. G1 now only allows allocations out of young regions (with the only exception being humongous regions). b) The thread that allocates a new region (which is now guaranteed to be young) does not dirty all its cards. Each thread that successfully allocates out of a young region is now responsible for dirtying the cards that corresponding to the "block" that just got allocated. c) allocate_new_tlab() and mem_allocate() are now implemented differently and TLAB allocations are only done by allocate_new_tlab(). d) If a thread schedules an evacuation pause in order to satisfy an allocation request, it will perform the allocation at the end of the safepoint so that the thread that initiated the GC also gets "first pick" of any space made available by the GC. e) If a thread is unable to allocate a humongous object it will schedule an evacuation pause in case it reclaims enough regions so that the humongous allocation can be satisfied aftewards. f) The G1 policy is more careful to set the young list target length to be the survivor number +1. g) Lots of code tidy up, removal, refactoring to make future changes easier.

Reviewed-by: johnc, ysr
This commit is contained in:
Antonios Printezis 2010-08-24 17:24:33 -04:00
parent 8006fe8f75
commit bb23e30511
7 changed files with 985 additions and 374 deletions

View file

@ -458,8 +458,8 @@ void G1CollectorPolicy::calculate_young_list_min_length() {
double now_sec = os::elapsedTime();
double when_ms = _mmu_tracker->when_max_gc_sec(now_sec) * 1000.0;
double alloc_rate_ms = predict_alloc_rate_ms();
int min_regions = (int) ceil(alloc_rate_ms * when_ms);
int current_region_num = (int) _g1->young_list()->length();
size_t min_regions = (size_t) ceil(alloc_rate_ms * when_ms);
size_t current_region_num = _g1->young_list()->length();
_young_list_min_length = min_regions + current_region_num;
}
}
@ -473,9 +473,12 @@ void G1CollectorPolicy::calculate_young_list_target_length() {
_young_list_target_length = _young_list_fixed_length;
else
_young_list_target_length = _young_list_fixed_length / 2;
_young_list_target_length = MAX2(_young_list_target_length, (size_t)1);
}
// Make sure we allow the application to allocate at least one
// region before we need to do a collection again.
size_t min_length = _g1->young_list()->length() + 1;
_young_list_target_length = MAX2(_young_list_target_length, min_length);
calculate_survivors_policy();
}
@ -568,7 +571,7 @@ void G1CollectorPolicy::calculate_young_list_target_length(size_t rs_lengths) {
// we should have at least one region in the target young length
_young_list_target_length =
MAX2((size_t) 1, final_young_length + _recorded_survivor_regions);
final_young_length + _recorded_survivor_regions;
// let's keep an eye of how long we spend on this calculation
// right now, I assume that we'll print it when we need it; we
@ -617,8 +620,7 @@ void G1CollectorPolicy::calculate_young_list_target_length(size_t rs_lengths) {
_young_list_min_length);
#endif // TRACE_CALC_YOUNG_LENGTH
// we'll do the pause as soon as possible by choosing the minimum
_young_list_target_length =
MAX2(_young_list_min_length, (size_t) 1);
_young_list_target_length = _young_list_min_length;
}
_rs_lengths_prediction = rs_lengths;
@ -801,7 +803,7 @@ void G1CollectorPolicy::record_full_collection_end() {
_survivor_surv_rate_group->reset();
calculate_young_list_min_length();
calculate_young_list_target_length();
}
}
void G1CollectorPolicy::record_before_bytes(size_t bytes) {
_bytes_in_to_space_before_gc += bytes;
@ -824,9 +826,9 @@ void G1CollectorPolicy::record_collection_pause_start(double start_time_sec,
gclog_or_tty->print(" (%s)", full_young_gcs() ? "young" : "partial");
}
assert(_g1->used_regions() == _g1->recalculate_used_regions(),
"sanity");
assert(_g1->used() == _g1->recalculate_used(), "sanity");
assert(_g1->used() == _g1->recalculate_used(),
err_msg("sanity, used: "SIZE_FORMAT" recalculate_used: "SIZE_FORMAT,
_g1->used(), _g1->recalculate_used()));
double s_w_t_ms = (start_time_sec - _stop_world_start) * 1000.0;
_all_stop_world_times_ms->add(s_w_t_ms);
@ -2266,24 +2268,13 @@ void G1CollectorPolicy::print_yg_surv_rate_info() const {
#endif // PRODUCT
}
bool
G1CollectorPolicy::should_add_next_region_to_young_list() {
assert(in_young_gc_mode(), "should be in young GC mode");
bool ret;
size_t young_list_length = _g1->young_list()->length();
size_t young_list_max_length = _young_list_target_length;
if (G1FixedEdenSize) {
young_list_max_length -= _max_survivor_regions;
}
if (young_list_length < young_list_max_length) {
ret = true;
void
G1CollectorPolicy::update_region_num(bool young) {
if (young) {
++_region_num_young;
} else {
ret = false;
++_region_num_tenured;
}
return ret;
}
#ifndef PRODUCT
@ -2327,32 +2318,6 @@ void G1CollectorPolicy::calculate_survivors_policy()
}
}
bool
G1CollectorPolicy_BestRegionsFirst::should_do_collection_pause(size_t
word_size) {
assert(_g1->regions_accounted_for(), "Region leakage!");
double max_pause_time_ms = _mmu_tracker->max_gc_time() * 1000.0;
size_t young_list_length = _g1->young_list()->length();
size_t young_list_max_length = _young_list_target_length;
if (G1FixedEdenSize) {
young_list_max_length -= _max_survivor_regions;
}
bool reached_target_length = young_list_length >= young_list_max_length;
if (in_young_gc_mode()) {
if (reached_target_length) {
assert( young_list_length > 0 && _g1->young_list()->length() > 0,
"invariant" );
return true;
}
} else {
guarantee( false, "should not reach here" );
}
return false;
}
#ifndef PRODUCT
class HRSortIndexIsOKClosure: public HeapRegionClosure {
CollectionSetChooser* _chooser;