Skip to content

Commit 81bad59

Browse files
Aditya Mandaleekakstefanj
Aditya Mandaleeka
authored andcommittedJun 8, 2021
8257774: G1: Trigger collect when free region count drops below threshold to prevent evacuation failures
Reviewed-by: sjohanss, tschatzl
1 parent 341f676 commit 81bad59

15 files changed

+210
-37
lines changed
 

‎src/hotspot/share/gc/g1/g1AllocRegion.hpp

+11-10
Original file line numberDiff line numberDiff line change
@@ -164,21 +164,22 @@ class G1AllocRegion : public CHeapObj<mtGC> {
164164
size_t desired_word_size,
165165
size_t* actual_word_size);
166166

167-
// Second-level allocation: Should be called while holding a
168-
// lock. It will try to first allocate lock-free out of the active
169-
// region or, if it's unable to, it will try to replace the active
170-
// alloc region with a new one. We require that the caller takes the
171-
// appropriate lock before calling this so that it is easier to make
172-
// it conform to its locking protocol.
173167
inline HeapWord* attempt_allocation_locked(size_t word_size);
174-
// Same as attempt_allocation_locked(size_t, bool), but allowing specification
175-
// of minimum word size of the block in min_word_size, and the maximum word
176-
// size of the allocation in desired_word_size. The actual size of the block is
177-
// returned in actual_word_size.
168+
// Second-level allocation: Should be called while holding a
169+
// lock. We require that the caller takes the appropriate lock
170+
// before calling this so that it is easier to make it conform
171+
// to the locking protocol. The min and desired word size allow
172+
// specifying a minimum and maximum size of the allocation. The
173+
// actual size of allocation is returned in actual_word_size.
178174
inline HeapWord* attempt_allocation_locked(size_t min_word_size,
179175
size_t desired_word_size,
180176
size_t* actual_word_size);
181177

178+
// Perform an allocation out of a new allocation region, retiring the current one.
179+
inline HeapWord* attempt_allocation_using_new_region(size_t min_word_size,
180+
size_t desired_word_size,
181+
size_t* actual_word_size);
182+
182183
// Should be called to allocate a new region even if the max of this
183184
// type of regions has been reached. Should only be called if other
184185
// allocation attempts have failed and we are not holding a valid

‎src/hotspot/share/gc/g1/g1AllocRegion.inline.hpp

+7-4
Original file line numberDiff line numberDiff line change
@@ -99,16 +99,19 @@ inline HeapWord* G1AllocRegion::attempt_allocation_locked(size_t word_size) {
9999
inline HeapWord* G1AllocRegion::attempt_allocation_locked(size_t min_word_size,
100100
size_t desired_word_size,
101101
size_t* actual_word_size) {
102-
// First we have to redo the allocation, assuming we're holding the
103-
// appropriate lock, in case another thread changed the region while
104-
// we were waiting to get the lock.
105102
HeapWord* result = attempt_allocation(min_word_size, desired_word_size, actual_word_size);
106103
if (result != NULL) {
107104
return result;
108105
}
109106

107+
return attempt_allocation_using_new_region(min_word_size, desired_word_size, actual_word_size);
108+
}
109+
110+
inline HeapWord* G1AllocRegion::attempt_allocation_using_new_region(size_t min_word_size,
111+
size_t desired_word_size,
112+
size_t* actual_word_size) {
110113
retire(true /* fill_up */);
111-
result = new_alloc_region_and_allocate(desired_word_size, false /* force */);
114+
HeapWord* result = new_alloc_region_and_allocate(desired_word_size, false /* force */);
112115
if (result != NULL) {
113116
*actual_word_size = desired_word_size;
114117
trace("alloc locked (second attempt)", min_word_size, desired_word_size, *actual_word_size, result);

‎src/hotspot/share/gc/g1/g1Allocator.hpp

+9
Original file line numberDiff line numberDiff line change
@@ -112,10 +112,19 @@ class G1Allocator : public CHeapObj<mtGC> {
112112

113113
// Allocate blocks of memory during mutator time.
114114

115+
// Attempt allocation in the current alloc region.
115116
inline HeapWord* attempt_allocation(size_t min_word_size,
116117
size_t desired_word_size,
117118
size_t* actual_word_size);
119+
120+
// Attempt allocation, retiring the current region and allocating a new one. It is
121+
// assumed that attempt_allocation() has been tried and failed already first.
122+
inline HeapWord* attempt_allocation_using_new_region(size_t word_size);
123+
124+
// This is to be called when holding an appropriate lock. It first tries in the
125+
// current allocation region, and then attempts an allocation using a new region.
118126
inline HeapWord* attempt_allocation_locked(size_t word_size);
127+
119128
inline HeapWord* attempt_allocation_force(size_t word_size);
120129

121130
size_t unsafe_max_tlab_alloc();

‎src/hotspot/share/gc/g1/g1Allocator.inline.hpp

+13
Original file line numberDiff line numberDiff line change
@@ -53,16 +53,29 @@ inline HeapWord* G1Allocator::attempt_allocation(size_t min_word_size,
5353
size_t desired_word_size,
5454
size_t* actual_word_size) {
5555
uint node_index = current_node_index();
56+
5657
HeapWord* result = mutator_alloc_region(node_index)->attempt_retained_allocation(min_word_size, desired_word_size, actual_word_size);
5758
if (result != NULL) {
5859
return result;
5960
}
61+
6062
return mutator_alloc_region(node_index)->attempt_allocation(min_word_size, desired_word_size, actual_word_size);
6163
}
6264

65+
inline HeapWord* G1Allocator::attempt_allocation_using_new_region(size_t word_size) {
66+
uint node_index = current_node_index();
67+
size_t temp;
68+
HeapWord* result = mutator_alloc_region(node_index)->attempt_allocation_using_new_region(word_size, word_size, &temp);
69+
assert(result != NULL || mutator_alloc_region(node_index)->get() == NULL,
70+
"Must not have a mutator alloc region if there is no memory, but is " PTR_FORMAT,
71+
p2i(mutator_alloc_region(node_index)->get()));
72+
return result;
73+
}
74+
6375
inline HeapWord* G1Allocator::attempt_allocation_locked(size_t word_size) {
6476
uint node_index = current_node_index();
6577
HeapWord* result = mutator_alloc_region(node_index)->attempt_allocation_locked(word_size);
78+
6679
assert(result != NULL || mutator_alloc_region(node_index)->get() == NULL,
6780
"Must not have a mutator alloc region if there is no memory, but is " PTR_FORMAT, p2i(mutator_alloc_region(node_index)->get()));
6881
return result;

‎src/hotspot/share/gc/g1/g1CollectedHeap.cpp

+43-21
Original file line numberDiff line numberDiff line change
@@ -394,26 +394,42 @@ HeapWord* G1CollectedHeap::attempt_allocation_slow(size_t word_size) {
394394
HeapWord* result = NULL;
395395
for (uint try_count = 1, gclocker_retry_count = 0; /* we'll return */; try_count += 1) {
396396
bool should_try_gc;
397+
bool preventive_collection_required = false;
397398
uint gc_count_before;
398399

399400
{
400401
MutexLocker x(Heap_lock);
401-
result = _allocator->attempt_allocation_locked(word_size);
402+
403+
// Now that we have the lock, we first retry the allocation in case another
404+
// thread changed the region while we were waiting to acquire the lock.
405+
size_t actual_size;
406+
result = _allocator->attempt_allocation(word_size, word_size, &actual_size);
402407
if (result != NULL) {
403408
return result;
404409
}
405410

406-
// If the GCLocker is active and we are bound for a GC, try expanding young gen.
407-
// This is different to when only GCLocker::needs_gc() is set: try to avoid
408-
// waiting because the GCLocker is active to not wait too long.
409-
if (GCLocker::is_active_and_needs_gc() && policy()->can_expand_young_list()) {
410-
// No need for an ergo message here, can_expand_young_list() does this when
411-
// it returns true.
412-
result = _allocator->attempt_allocation_force(word_size);
411+
preventive_collection_required = policy()->preventive_collection_required(1);
412+
if (!preventive_collection_required) {
413+
// We've already attempted a lock-free allocation above, so we don't want to
414+
// do it again. Let's jump straight to replacing the active region.
415+
result = _allocator->attempt_allocation_using_new_region(word_size);
413416
if (result != NULL) {
414417
return result;
415418
}
419+
420+
// If the GCLocker is active and we are bound for a GC, try expanding young gen.
421+
// This is different to when only GCLocker::needs_gc() is set: try to avoid
422+
// waiting because the GCLocker is active to not wait too long.
423+
if (GCLocker::is_active_and_needs_gc() && policy()->can_expand_young_list()) {
424+
// No need for an ergo message here, can_expand_young_list() does this when
425+
// it returns true.
426+
result = _allocator->attempt_allocation_force(word_size);
427+
if (result != NULL) {
428+
return result;
429+
}
430+
}
416431
}
432+
417433
// Only try a GC if the GCLocker does not signal the need for a GC. Wait until
418434
// the GCLocker initiated GC has been performed and then retry. This includes
419435
// the case when the GC Locker is not active but has not been performed.
@@ -423,9 +439,10 @@ HeapWord* G1CollectedHeap::attempt_allocation_slow(size_t word_size) {
423439
}
424440

425441
if (should_try_gc) {
442+
GCCause::Cause gc_cause = preventive_collection_required ? GCCause::_g1_preventive_collection
443+
: GCCause::_g1_inc_collection_pause;
426444
bool succeeded;
427-
result = do_collection_pause(word_size, gc_count_before, &succeeded,
428-
GCCause::_g1_inc_collection_pause);
445+
result = do_collection_pause(word_size, gc_count_before, &succeeded, gc_cause);
429446
if (result != NULL) {
430447
assert(succeeded, "only way to get back a non-NULL result");
431448
log_trace(gc, alloc)("%s: Successfully scheduled collection returning " PTR_FORMAT,
@@ -840,21 +857,25 @@ HeapWord* G1CollectedHeap::attempt_allocation_humongous(size_t word_size) {
840857
HeapWord* result = NULL;
841858
for (uint try_count = 1, gclocker_retry_count = 0; /* we'll return */; try_count += 1) {
842859
bool should_try_gc;
860+
bool preventive_collection_required = false;
843861
uint gc_count_before;
844862

845863

846864
{
847865
MutexLocker x(Heap_lock);
848866

849-
// Given that humongous objects are not allocated in young
850-
// regions, we'll first try to do the allocation without doing a
851-
// collection hoping that there's enough space in the heap.
852-
result = humongous_obj_allocate(word_size);
853-
if (result != NULL) {
854-
size_t size_in_regions = humongous_obj_size_in_regions(word_size);
855-
policy()->old_gen_alloc_tracker()->
856-
add_allocated_humongous_bytes_since_last_gc(size_in_regions * HeapRegion::GrainBytes);
857-
return result;
867+
size_t size_in_regions = humongous_obj_size_in_regions(word_size);
868+
preventive_collection_required = policy()->preventive_collection_required((uint)size_in_regions);
869+
if (!preventive_collection_required) {
870+
// Given that humongous objects are not allocated in young
871+
// regions, we'll first try to do the allocation without doing a
872+
// collection hoping that there's enough space in the heap.
873+
result = humongous_obj_allocate(word_size);
874+
if (result != NULL) {
875+
policy()->old_gen_alloc_tracker()->
876+
add_allocated_humongous_bytes_since_last_gc(size_in_regions * HeapRegion::GrainBytes);
877+
return result;
878+
}
858879
}
859880

860881
// Only try a GC if the GCLocker does not signal the need for a GC. Wait until
@@ -866,9 +887,10 @@ HeapWord* G1CollectedHeap::attempt_allocation_humongous(size_t word_size) {
866887
}
867888

868889
if (should_try_gc) {
890+
GCCause::Cause gc_cause = preventive_collection_required ? GCCause::_g1_preventive_collection
891+
: GCCause::_g1_humongous_allocation;
869892
bool succeeded;
870-
result = do_collection_pause(word_size, gc_count_before, &succeeded,
871-
GCCause::_g1_humongous_allocation);
893+
result = do_collection_pause(word_size, gc_count_before, &succeeded, gc_cause);
872894
if (result != NULL) {
873895
assert(succeeded, "only way to get back a non-NULL result");
874896
log_trace(gc, alloc)("%s: Successfully scheduled collection returning " PTR_FORMAT,

‎src/hotspot/share/gc/g1/g1CollectionSet.cpp

+4
Original file line numberDiff line numberDiff line change
@@ -111,6 +111,10 @@ void G1CollectionSet::clear_candidates() {
111111
_candidates = NULL;
112112
}
113113

114+
bool G1CollectionSet::has_candidates() {
115+
return _candidates != NULL && !_candidates->is_empty();
116+
}
117+
114118
void G1CollectionSet::set_recorded_rs_length(size_t rs_length) {
115119
_recorded_rs_length = rs_length;
116120
}

‎src/hotspot/share/gc/g1/g1CollectionSet.hpp

+1
Original file line numberDiff line numberDiff line change
@@ -272,6 +272,7 @@ class G1CollectionSet {
272272
void initialize(uint max_region_length);
273273

274274
void clear_candidates();
275+
bool has_candidates();
275276

276277
void set_candidates(G1CollectionSetCandidates* candidates) {
277278
assert(_candidates == NULL, "Trying to replace collection set candidates.");

‎src/hotspot/share/gc/g1/g1Policy.cpp

+84
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,8 @@ G1Policy::G1Policy(STWGCTimer* gc_timer) :
6868
_reserve_regions(0),
6969
_young_gen_sizer(),
7070
_free_regions_at_end_of_collection(0),
71+
_predicted_surviving_bytes_from_survivor(0),
72+
_predicted_surviving_bytes_from_old(0),
7173
_rs_length(0),
7274
_rs_length_prediction(0),
7375
_pending_cards_at_gc_start(0),
@@ -450,6 +452,7 @@ void G1Policy::record_full_collection_end() {
450452
// also call this on any additional surv rate groups
451453

452454
_free_regions_at_end_of_collection = _g1h->num_free_regions();
455+
update_survival_estimates_for_next_collection();
453456
_survivor_surv_rate_group->reset();
454457
update_young_list_max_and_target_length();
455458
update_rs_length_prediction();
@@ -779,6 +782,7 @@ void G1Policy::record_collection_pause_end(double pause_time_ms, bool concurrent
779782
_free_regions_at_end_of_collection = _g1h->num_free_regions();
780783

781784
update_rs_length_prediction();
785+
update_survival_estimates_for_next_collection();
782786

783787
// Do not update dynamic IHOP due to G1 periodic collection as it is highly likely
784788
// that in this case we are not running in a "normal" operating mode.
@@ -1400,6 +1404,86 @@ void G1Policy::calculate_optional_collection_set_regions(G1CollectionSetCandidat
14001404
num_optional_regions, max_optional_regions, prediction_ms);
14011405
}
14021406

1407+
// Number of regions required to store the given number of bytes, taking
1408+
// into account the target amount of wasted space in PLABs.
1409+
static size_t get_num_regions_adjust_for_plab_waste(size_t byte_count) {
1410+
size_t byte_count_adjusted = byte_count * (size_t)(100 + TargetPLABWastePct) / 100.0;
1411+
1412+
// Round up the region count
1413+
return (byte_count_adjusted + HeapRegion::GrainBytes - 1) / HeapRegion::GrainBytes;
1414+
}
1415+
1416+
bool G1Policy::preventive_collection_required(uint alloc_region_count) {
1417+
if (!G1AllowPreventiveGC || !Universe::is_fully_initialized()) {
1418+
// Don't attempt any preventive GC's if the feature is disabled,
1419+
// or before initialization is complete.
1420+
return false;
1421+
}
1422+
1423+
if (_g1h->young_regions_count() == 0 && !_collection_set->has_candidates()) {
1424+
return false;
1425+
}
1426+
1427+
uint eden_count = _g1h->eden_regions_count();
1428+
size_t const eden_surv_bytes_pred = _eden_surv_rate_group->accum_surv_rate_pred(eden_count) * HeapRegion::GrainBytes;
1429+
size_t const total_young_predicted_surviving_bytes = eden_surv_bytes_pred + _predicted_surviving_bytes_from_survivor;
1430+
1431+
uint required_regions = (uint)(get_num_regions_adjust_for_plab_waste(total_young_predicted_surviving_bytes) +
1432+
get_num_regions_adjust_for_plab_waste(_predicted_surviving_bytes_from_old));
1433+
1434+
if (required_regions > _g1h->num_free_regions() - alloc_region_count) {
1435+
log_debug(gc, ergo, cset)("Preventive GC, insufficient free regions. Predicted need %u. Curr Eden %u (Pred %u). Curr Survivor %u (Pred %u). Curr Old %u (Pred %u) Free %u Alloc %u",
1436+
required_regions,
1437+
eden_count,
1438+
(uint)get_num_regions_adjust_for_plab_waste(eden_surv_bytes_pred),
1439+
_g1h->survivor_regions_count(),
1440+
(uint)get_num_regions_adjust_for_plab_waste(_predicted_surviving_bytes_from_survivor),
1441+
_g1h->old_regions_count(),
1442+
(uint)get_num_regions_adjust_for_plab_waste(_predicted_surviving_bytes_from_old),
1443+
_g1h->num_free_regions(),
1444+
alloc_region_count);
1445+
1446+
return true;
1447+
}
1448+
1449+
return false;
1450+
}
1451+
1452+
void G1Policy::update_survival_estimates_for_next_collection() {
1453+
// Predict the number of bytes of surviving objects from survivor and old
1454+
// regions and update the associated members.
1455+
1456+
// Survivor regions
1457+
size_t survivor_bytes = 0;
1458+
const GrowableArray<HeapRegion*>* survivor_regions = _g1h->survivor()->regions();
1459+
for (GrowableArrayIterator<HeapRegion*> it = survivor_regions->begin();
1460+
it != survivor_regions->end();
1461+
++it) {
1462+
survivor_bytes += predict_bytes_to_copy(*it);
1463+
}
1464+
1465+
_predicted_surviving_bytes_from_survivor = survivor_bytes;
1466+
1467+
// Old regions
1468+
if (!_collection_set->has_candidates()) {
1469+
_predicted_surviving_bytes_from_old = 0;
1470+
return;
1471+
}
1472+
1473+
// Use the minimum old gen collection set as conservative estimate for the number
1474+
// of regions to take for this calculation.
1475+
G1CollectionSetCandidates *candidates = _collection_set->candidates();
1476+
uint iterate_count = MIN2(candidates->num_remaining(), calc_min_old_cset_length(candidates));
1477+
uint current_index = candidates->cur_idx();
1478+
size_t old_bytes = 0;
1479+
for (uint i = 0; i < iterate_count; i++) {
1480+
HeapRegion *region = candidates->at(current_index + i);
1481+
old_bytes += predict_bytes_to_copy(region);
1482+
}
1483+
1484+
_predicted_surviving_bytes_from_old = old_bytes;
1485+
}
1486+
14031487
void G1Policy::transfer_survivors_to_cset(const G1SurvivorRegions* survivors) {
14041488
note_start_adding_survivor_regions();
14051489

‎src/hotspot/share/gc/g1/g1Policy.hpp

+15
Original file line numberDiff line numberDiff line change
@@ -98,6 +98,11 @@ class G1Policy: public CHeapObj<mtGC> {
9898

9999
uint _free_regions_at_end_of_collection;
100100

101+
// These values are predictions of how much we think will survive in each
102+
// section of the heap.
103+
size_t _predicted_surviving_bytes_from_survivor;
104+
size_t _predicted_surviving_bytes_from_old;
105+
101106
size_t _rs_length;
102107

103108
size_t _rs_length_prediction;
@@ -345,7 +350,17 @@ class G1Policy: public CHeapObj<mtGC> {
345350
double time_remaining_ms,
346351
uint& num_optional_regions);
347352

353+
// Returns whether a collection should be done proactively, taking into
354+
// account the current number of free regions and the expected survival
355+
// rates in each section of the heap.
356+
bool preventive_collection_required(uint region_count);
357+
348358
private:
359+
360+
// Predict the number of bytes of surviving objects from survivor and old
361+
// regions and update the associated members.
362+
void update_survival_estimates_for_next_collection();
363+
349364
// Set the state to start a concurrent marking cycle and clear
350365
// _initiate_conc_mark_if_possible because it has now been
351366
// acted on.

‎src/hotspot/share/gc/g1/g1VMOperations.cpp

+6-1
Original file line numberDiff line numberDiff line change
@@ -119,10 +119,15 @@ VM_G1CollectForAllocation::VM_G1CollectForAllocation(size_t word_size,
119119
_gc_cause = gc_cause;
120120
}
121121

122+
bool VM_G1CollectForAllocation::should_try_allocation_before_gc() {
123+
// Don't allocate before a preventive GC.
124+
return _gc_cause != GCCause::_g1_preventive_collection;
125+
}
126+
122127
void VM_G1CollectForAllocation::doit() {
123128
G1CollectedHeap* g1h = G1CollectedHeap::heap();
124129

125-
if (_word_size > 0) {
130+
if (should_try_allocation_before_gc() && _word_size > 0) {
126131
// An allocation has been requested. So, try to do that first.
127132
_result = g1h->attempt_allocation_at_safepoint(_word_size,
128133
false /* expect_null_cur_alloc_region */);

1 commit comments

Comments
 (1)

openjdk-notifier[bot] commented on Jun 8, 2021

@openjdk-notifier[bot]
Please sign in to comment.