Skip to content

Commit 64b44a8

Browse files
author
William Kemper
committedApr 15, 2024
8329790: GenShen: Old regions that are pinned during final mark are not made parseable
Reviewed-by: kdnilsen
1 parent 0578af8 commit 64b44a8

File tree

3 files changed

+32
-23
lines changed

3 files changed

+32
-23
lines changed
 

‎src/hotspot/share/gc/shenandoah/heuristics/shenandoahOldHeuristics.cpp

+23-17
Original file line numberDiff line numberDiff line change
@@ -70,7 +70,6 @@ ShenandoahOldHeuristics::ShenandoahOldHeuristics(ShenandoahOldGeneration* genera
7070
}
7171

7272
bool ShenandoahOldHeuristics::prime_collection_set(ShenandoahCollectionSet* collection_set) {
73-
auto heap = ShenandoahGenerationalHeap::heap();
7473
if (unprocessed_old_collection_candidates() == 0) {
7574
return false;
7675
}
@@ -86,7 +85,7 @@ bool ShenandoahOldHeuristics::prime_collection_set(ShenandoahCollectionSet* coll
8685
// of memory that can still be evacuated. We address this by reducing the evacuation budget by the amount
8786
// of live memory in that region and by the amount of unallocated memory in that region if the evacuation
8887
// budget is constrained by availability of free memory.
89-
const size_t old_evacuation_reserve = heap->old_generation()->get_evacuation_reserve();
88+
const size_t old_evacuation_reserve = _old_generation->get_evacuation_reserve();
9089
const size_t old_evacuation_budget = (size_t) ((double) old_evacuation_reserve / ShenandoahOldEvacWaste);
9190
size_t unfragmented_available = _old_generation->free_unaffiliated_regions() * ShenandoahHeapRegion::region_size_bytes();
9291
size_t fragmented_available;
@@ -310,25 +309,26 @@ void ShenandoahOldHeuristics::prepare_for_old_collections() {
310309

311310
const size_t num_regions = heap->num_regions();
312311
size_t cand_idx = 0;
313-
size_t total_garbage = 0;
314312
size_t immediate_garbage = 0;
315313
size_t immediate_regions = 0;
316314
size_t live_data = 0;
317315

318316
RegionData* candidates = _region_data;
319317
for (size_t i = 0; i < num_regions; i++) {
320318
ShenandoahHeapRegion* region = heap->get_region(i);
321-
if (!_old_generation->contains(region)) {
319+
if (!region->is_old()) {
322320
continue;
323321
}
324322

325323
size_t garbage = region->garbage();
326324
size_t live_bytes = region->get_live_data_bytes();
327-
total_garbage += garbage;
328325
live_data += live_bytes;
329326

330-
// Only place regular regions into the candidate set
331-
if (region->is_regular()) {
327+
if (region->is_regular() || region->is_regular_pinned()) {
328+
// Only place regular or pinned regions with live data into the candidate set.
329+
// Pinned regions cannot be evacuated, but we are not actually choosing candidates
330+
// for the collection set here. That happens later during the next young GC cycle,
331+
// by which time, the pinned region may no longer be pinned.
332332
if (!region->has_live()) {
333333
assert(!region->is_pinned(), "Pinned region should have live (pinned) objects.");
334334
region->make_trash_immediate();
@@ -341,6 +341,9 @@ void ShenandoahOldHeuristics::prepare_for_old_collections() {
341341
cand_idx++;
342342
}
343343
} else if (region->is_humongous_start()) {
344+
// This will handle humongous start regions whether they are also pinned, or not.
345+
// If they are pinned, we expect them to hold live data, so they will not be
346+
// turned into immediate garbage.
344347
if (!region->has_live()) {
345348
assert(!region->is_pinned(), "Pinned region should have live (pinned) objects.");
346349
// The humongous object is dead, we can just return this region and the continuations
@@ -385,12 +388,12 @@ void ShenandoahOldHeuristics::prepare_for_old_collections() {
385388
// Enlightened interpretation: collect regions that have less than this amount of live.
386389
const size_t live_threshold = region_size_bytes - garbage_threshold;
387390

388-
size_t candidates_garbage = 0;
389391
_last_old_region = (uint)cand_idx;
390392
_last_old_collection_candidate = (uint)cand_idx;
391393
_next_old_collection_candidate = 0;
392394

393395
size_t unfragmented = 0;
396+
size_t candidates_garbage = 0;
394397

395398
for (size_t i = 0; i < cand_idx; i++) {
396399
size_t live = candidates[i]._u._live_data;
@@ -405,7 +408,11 @@ void ShenandoahOldHeuristics::prepare_for_old_collections() {
405408
unfragmented += region_free;
406409
}
407410

411+
// defrag_count represents regions that are placed into the old collection set in order to defragment the memory
412+
// that we try to "reserve" for humongous allocations.
408413
size_t defrag_count = 0;
414+
size_t total_uncollected_old_regions = _last_old_region - _last_old_collection_candidate;
415+
409416
if (cand_idx > _last_old_collection_candidate) {
410417
// Above, we have added into the set of mixed-evacuation candidates all old-gen regions for which the live memory
411418
// that they contain is below a particular old-garbage threshold. Regions that were not selected for the collection
@@ -425,7 +432,6 @@ void ShenandoahOldHeuristics::prepare_for_old_collections() {
425432
const size_t first_unselected_old_region = candidates[_last_old_collection_candidate]._region->index();
426433
const size_t last_unselected_old_region = candidates[cand_idx - 1]._region->index();
427434
size_t span_of_uncollected_regions = 1 + last_unselected_old_region - first_unselected_old_region;
428-
size_t total_uncollected_old_regions = cand_idx - _last_old_collection_candidate;
429435

430436
// Add no more than 1/8 of the existing old-gen regions to the set of mixed evacuation candidates.
431437
const int MAX_FRACTION_OF_HUMONGOUS_DEFRAG_REGIONS = 8;
@@ -436,7 +442,8 @@ void ShenandoahOldHeuristics::prepare_for_old_collections() {
436442
while ((defrag_count < bound_on_additional_regions) &&
437443
(total_uncollected_old_regions < 15 * span_of_uncollected_regions / 16)) {
438444
ShenandoahHeapRegion* r = candidates[_last_old_collection_candidate]._region;
439-
assert (r->is_regular(), "Only regular regions are in the candidate set");
445+
assert(r->is_regular() || r->is_regular_pinned(), "Region " SIZE_FORMAT " has wrong state for collection: %s",
446+
r->index(), ShenandoahHeapRegion::region_state_to_string(r->state()));
440447
const size_t region_garbage = candidates[_last_old_collection_candidate]._region->garbage();
441448
const size_t region_free = r->free();
442449
candidates_garbage += region_garbage;
@@ -457,13 +464,12 @@ void ShenandoahOldHeuristics::prepare_for_old_collections() {
457464
const size_t mixed_evac_live = old_candidates * region_size_bytes - (candidates_garbage + unfragmented);
458465
set_unprocessed_old_collection_candidates_live_memory(mixed_evac_live);
459466

460-
log_info(gc)("Old-Gen Collectable Garbage: " SIZE_FORMAT "%s "
461-
"consolidated with free: " SIZE_FORMAT "%s, over " SIZE_FORMAT " regions (humongous defragmentation: "
462-
SIZE_FORMAT " regions), Old-Gen Immediate Garbage: " SIZE_FORMAT "%s over " SIZE_FORMAT " regions.",
463-
byte_size_in_proper_unit(collectable_garbage), proper_unit_for_byte_size(collectable_garbage),
464-
byte_size_in_proper_unit(unfragmented), proper_unit_for_byte_size(unfragmented),
465-
old_candidates, defrag_count,
466-
byte_size_in_proper_unit(immediate_garbage), proper_unit_for_byte_size(immediate_garbage), immediate_regions);
467+
log_info(gc)("Old-Gen Collectable Garbage: " PROPERFMT " consolidated with free: " PROPERFMT ", over " SIZE_FORMAT " regions",
468+
PROPERFMTARGS(collectable_garbage), PROPERFMTARGS(unfragmented), old_candidates);
469+
log_info(gc)("Old-Gen Immediate Garbage: " PROPERFMT " over " SIZE_FORMAT " regions",
470+
PROPERFMTARGS(immediate_garbage), immediate_regions);
471+
log_info(gc)("Old regions selected for defragmentation: " SIZE_FORMAT, defrag_count);
472+
log_info(gc)("Old regions not selected: " SIZE_FORMAT, total_uncollected_old_regions);
467473

468474
if (unprocessed_old_collection_candidates() > 0) {
469475
_old_generation->transition_to(ShenandoahOldGeneration::EVACUATING);

‎src/hotspot/share/gc/shenandoah/shenandoahHeapRegion.hpp

+4
Original file line numberDiff line numberDiff line change
@@ -124,6 +124,7 @@ class ShenandoahHeapRegion {
124124
_REGION_STATES_NUM // last
125125
};
126126

127+
public:
127128
static const char* region_state_to_string(RegionState s) {
128129
switch (s) {
129130
case _empty_uncommitted: return "Empty Uncommitted";
@@ -142,6 +143,7 @@ class ShenandoahHeapRegion {
142143
}
143144
}
144145

146+
private:
145147
// This method protects from accidental changes in enum order:
146148
int region_state_to_ordinal(RegionState s) const {
147149
switch (s) {
@@ -200,6 +202,8 @@ class ShenandoahHeapRegion {
200202
bool is_committed() const { return !is_empty_uncommitted(); }
201203
bool is_cset() const { return _state == _cset || _state == _pinned_cset; }
202204
bool is_pinned() const { return _state == _pinned || _state == _pinned_cset || _state == _pinned_humongous_start; }
205+
bool is_regular_pinned() const { return _state == _pinned; }
206+
203207
inline bool is_young() const;
204208
inline bool is_old() const;
205209
inline bool is_affiliated() const;

‎src/hotspot/share/gc/shenandoah/shenandoahOldGeneration.cpp

+5-6
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,7 @@ class ShenandoahFlushAllSATB : public ThreadClosure {
5555
explicit ShenandoahFlushAllSATB(SATBMarkQueueSet& satb_qset) :
5656
_satb_qset(satb_qset) {}
5757

58-
void do_thread(Thread* thread) {
58+
void do_thread(Thread* thread) override {
5959
// Transfer any partial buffer to the qset for completed buffer processing.
6060
_satb_qset.flush_queue(ShenandoahThreadLocalData::satb_mark_queue(thread));
6161
}
@@ -75,7 +75,7 @@ class ShenandoahProcessOldSATB : public SATBBufferClosure {
7575
_mark_context(_heap->marking_context()),
7676
_trashed_oops(0) {}
7777

78-
void do_buffer(void** buffer, size_t size) {
78+
void do_buffer(void** buffer, size_t size) override {
7979
assert(size == 0 || !_heap->has_forwarded_objects() || _heap->is_concurrent_old_mark_in_progress(), "Forwarded objects are not expected here");
8080
for (size_t i = 0; i < size; ++i) {
8181
oop *p = (oop *) &buffer[i];
@@ -112,7 +112,7 @@ class ShenandoahPurgeSATBTask : public WorkerTask {
112112
}
113113
}
114114

115-
void work(uint worker_id) {
115+
void work(uint worker_id) override {
116116
ShenandoahParallelWorkerSession worker_session(worker_id);
117117
ShenandoahSATBMarkQueueSet &satb_queues = ShenandoahBarrierSet::satb_mark_queue_set();
118118
ShenandoahFlushAllSATB flusher(satb_queues);
@@ -144,7 +144,7 @@ class ShenandoahConcurrentCoalesceAndFillTask : public WorkerTask {
144144
_is_preempted(false) {
145145
}
146146

147-
void work(uint worker_id) {
147+
void work(uint worker_id) override {
148148
for (uint region_idx = worker_id; region_idx < _coalesce_and_fill_region_count; region_idx += _nworkers) {
149149
ShenandoahHeapRegion* r = _coalesce_and_fill_region_array[region_idx];
150150
if (r->is_humongous()) {
@@ -305,15 +305,14 @@ bool ShenandoahOldGeneration::coalesce_and_fill() {
305305
WorkerThreads* workers = heap->workers();
306306
uint nworkers = workers->active_workers();
307307

308-
log_debug(gc)("Starting (or resuming) coalesce-and-fill of old heap regions");
309-
310308
// This code will see the same set of regions to fill on each resumption as it did
311309
// on the initial run. That's okay because each region keeps track of its own coalesce
312310
// and fill state. Regions that were filled on a prior attempt will not try to fill again.
313311
uint coalesce_and_fill_regions_count = heuristics()->get_coalesce_and_fill_candidates(_coalesce_and_fill_region_array);
314312
assert(coalesce_and_fill_regions_count <= heap->num_regions(), "Sanity");
315313
ShenandoahConcurrentCoalesceAndFillTask task(nworkers, _coalesce_and_fill_region_array, coalesce_and_fill_regions_count);
316314

315+
log_info(gc)("Starting (or resuming) coalesce-and-fill of " UINT32_FORMAT " old heap regions", coalesce_and_fill_regions_count);
317316
workers->run_task(&task);
318317
if (task.is_completed()) {
319318
abandon_collection_candidates();

2 commit comments

Comments
 (2)

earthling-amzn commented on Apr 29, 2024

@earthling-amzn
Contributor

/backport shenandoah-jdk21u

openjdk[bot] commented on Apr 29, 2024

@openjdk[bot]

@earthling-amzn the backport was successfully created on the branch backport-earthling-amzn-64b44a8c in my personal fork of openjdk/shenandoah-jdk21u. To create a pull request with this backport targeting openjdk/shenandoah-jdk21u:master, just click the following link:

➡️ Create pull request

The title of the pull request is automatically filled in correctly and below you find a suggestion for the pull request body:

Hi all,

This pull request contains a backport of commit 64b44a8c from the openjdk/shenandoah repository.

The commit being backported was authored by William Kemper on 15 Apr 2024 and was reviewed by Kelvin Nilsen.

Thanks!

If you need to update the source branch of the pull then run the following commands in a local clone of your personal fork of openjdk/shenandoah-jdk21u:

$ git fetch https://github.com/openjdk-bots/shenandoah-jdk21u.git backport-earthling-amzn-64b44a8c:backport-earthling-amzn-64b44a8c
$ git checkout backport-earthling-amzn-64b44a8c
# make changes
$ git add paths/to/changed/files
$ git commit --message 'Describe additional changes made'
$ git push https://github.com/openjdk-bots/shenandoah-jdk21u.git backport-earthling-amzn-64b44a8c
Please sign in to comment.