@@ -70,7 +70,6 @@ ShenandoahOldHeuristics::ShenandoahOldHeuristics(ShenandoahOldGeneration* genera
70
70
}
71
71
72
72
bool ShenandoahOldHeuristics::prime_collection_set (ShenandoahCollectionSet* collection_set) {
73
- auto heap = ShenandoahGenerationalHeap::heap ();
74
73
if (unprocessed_old_collection_candidates () == 0 ) {
75
74
return false ;
76
75
}
@@ -86,7 +85,7 @@ bool ShenandoahOldHeuristics::prime_collection_set(ShenandoahCollectionSet* coll
86
85
// of memory that can still be evacuated. We address this by reducing the evacuation budget by the amount
87
86
// of live memory in that region and by the amount of unallocated memory in that region if the evacuation
88
87
// 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 ();
90
89
const size_t old_evacuation_budget = (size_t ) ((double ) old_evacuation_reserve / ShenandoahOldEvacWaste);
91
90
size_t unfragmented_available = _old_generation->free_unaffiliated_regions () * ShenandoahHeapRegion::region_size_bytes ();
92
91
size_t fragmented_available;
@@ -310,25 +309,26 @@ void ShenandoahOldHeuristics::prepare_for_old_collections() {
310
309
311
310
const size_t num_regions = heap->num_regions ();
312
311
size_t cand_idx = 0 ;
313
- size_t total_garbage = 0 ;
314
312
size_t immediate_garbage = 0 ;
315
313
size_t immediate_regions = 0 ;
316
314
size_t live_data = 0 ;
317
315
318
316
RegionData* candidates = _region_data;
319
317
for (size_t i = 0 ; i < num_regions; i++) {
320
318
ShenandoahHeapRegion* region = heap->get_region (i);
321
- if (!_old_generation-> contains (region )) {
319
+ if (!region-> is_old ( )) {
322
320
continue ;
323
321
}
324
322
325
323
size_t garbage = region->garbage ();
326
324
size_t live_bytes = region->get_live_data_bytes ();
327
- total_garbage += garbage;
328
325
live_data += live_bytes;
329
326
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.
332
332
if (!region->has_live ()) {
333
333
assert (!region->is_pinned (), " Pinned region should have live (pinned) objects." );
334
334
region->make_trash_immediate ();
@@ -341,6 +341,9 @@ void ShenandoahOldHeuristics::prepare_for_old_collections() {
341
341
cand_idx++;
342
342
}
343
343
} 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.
344
347
if (!region->has_live ()) {
345
348
assert (!region->is_pinned (), " Pinned region should have live (pinned) objects." );
346
349
// The humongous object is dead, we can just return this region and the continuations
@@ -385,12 +388,12 @@ void ShenandoahOldHeuristics::prepare_for_old_collections() {
385
388
// Enlightened interpretation: collect regions that have less than this amount of live.
386
389
const size_t live_threshold = region_size_bytes - garbage_threshold;
387
390
388
- size_t candidates_garbage = 0 ;
389
391
_last_old_region = (uint )cand_idx;
390
392
_last_old_collection_candidate = (uint )cand_idx;
391
393
_next_old_collection_candidate = 0 ;
392
394
393
395
size_t unfragmented = 0 ;
396
+ size_t candidates_garbage = 0 ;
394
397
395
398
for (size_t i = 0 ; i < cand_idx; i++) {
396
399
size_t live = candidates[i]._u ._live_data ;
@@ -405,7 +408,11 @@ void ShenandoahOldHeuristics::prepare_for_old_collections() {
405
408
unfragmented += region_free;
406
409
}
407
410
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.
408
413
size_t defrag_count = 0 ;
414
+ size_t total_uncollected_old_regions = _last_old_region - _last_old_collection_candidate;
415
+
409
416
if (cand_idx > _last_old_collection_candidate) {
410
417
// Above, we have added into the set of mixed-evacuation candidates all old-gen regions for which the live memory
411
418
// 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() {
425
432
const size_t first_unselected_old_region = candidates[_last_old_collection_candidate]._region ->index ();
426
433
const size_t last_unselected_old_region = candidates[cand_idx - 1 ]._region ->index ();
427
434
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;
429
435
430
436
// Add no more than 1/8 of the existing old-gen regions to the set of mixed evacuation candidates.
431
437
const int MAX_FRACTION_OF_HUMONGOUS_DEFRAG_REGIONS = 8 ;
@@ -436,7 +442,8 @@ void ShenandoahOldHeuristics::prepare_for_old_collections() {
436
442
while ((defrag_count < bound_on_additional_regions) &&
437
443
(total_uncollected_old_regions < 15 * span_of_uncollected_regions / 16 )) {
438
444
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 ()));
440
447
const size_t region_garbage = candidates[_last_old_collection_candidate]._region ->garbage ();
441
448
const size_t region_free = r->free ();
442
449
candidates_garbage += region_garbage;
@@ -457,13 +464,12 @@ void ShenandoahOldHeuristics::prepare_for_old_collections() {
457
464
const size_t mixed_evac_live = old_candidates * region_size_bytes - (candidates_garbage + unfragmented);
458
465
set_unprocessed_old_collection_candidates_live_memory (mixed_evac_live);
459
466
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);
467
473
468
474
if (unprocessed_old_collection_candidates () > 0 ) {
469
475
_old_generation->transition_to (ShenandoahOldGeneration::EVACUATING);
2 commit comments
earthling-amzn commentedon Apr 29, 2024
/backport shenandoah-jdk21u
openjdk[bot] commentedon Apr 29, 2024
@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:
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: