@@ -80,15 +80,39 @@ void ShenandoahGlobalHeuristics::choose_global_collection_set(ShenandoahCollecti
80
80
size_t size, size_t actual_free,
81
81
size_t cur_young_garbage) const {
82
82
ShenandoahHeap* heap = ShenandoahHeap::heap ();
83
+ size_t region_size_bytes = ShenandoahHeapRegion::region_size_bytes ();
83
84
size_t capacity = heap->young_generation ()->max_capacity ();
84
- size_t garbage_threshold = ShenandoahHeapRegion:: region_size_bytes() * ShenandoahGarbageThreshold / 100 ;
85
- size_t ignore_threshold = ShenandoahHeapRegion:: region_size_bytes() * ShenandoahIgnoreGarbageThreshold / 100 ;
85
+ size_t garbage_threshold = region_size_bytes * ShenandoahGarbageThreshold / 100 ;
86
+ size_t ignore_threshold = region_size_bytes * ShenandoahIgnoreGarbageThreshold / 100 ;
86
87
const uint tenuring_threshold = heap->age_census ()->tenuring_threshold ();
87
88
88
89
size_t max_young_cset = (size_t ) (heap->get_young_evac_reserve () / ShenandoahEvacWaste);
89
90
size_t young_cur_cset = 0 ;
90
91
size_t max_old_cset = (size_t ) (heap->get_old_evac_reserve () / ShenandoahOldEvacWaste);
91
92
size_t old_cur_cset = 0 ;
93
+
94
+ // Figure out how many unaffiliated young regions are dedicated to mutator and to evacuator. Allow the young
95
+ // collector's unaffiliated regions to be transferred to old-gen if old-gen has more easily reclaimed garbage
96
+ // than young-gen. At the end of this cycle, any excess regions remaining in old-gen will be transferred back
97
+ // to young. Do not transfer the mutator's unaffiliated regions to old-gen. Those must remain available
98
+ // to the mutator as it needs to be able to consume this memory during concurrent GC.
99
+
100
+ size_t unaffiliated_young_regions = heap->young_generation ()->free_unaffiliated_regions ();
101
+ size_t unaffiliated_young_memory = unaffiliated_young_regions * region_size_bytes;
102
+
103
+ if (unaffiliated_young_memory > max_young_cset) {
104
+ size_t unaffiliated_mutator_memory = unaffiliated_young_memory - max_young_cset;
105
+ unaffiliated_young_memory -= unaffiliated_mutator_memory;
106
+ unaffiliated_young_regions = unaffiliated_young_memory / region_size_bytes; // round down
107
+ unaffiliated_young_memory = unaffiliated_young_regions * region_size_bytes;
108
+ }
109
+
110
+ // We'll affiliate these unaffiliated regions with either old or young, depending on need.
111
+ max_young_cset -= unaffiliated_young_memory;
112
+
113
+ // Keep track of how many regions we plan to transfer from young to old.
114
+ size_t regions_transferred_to_old = 0 ;
115
+
92
116
size_t free_target = (capacity * ShenandoahMinFreeThreshold) / 100 + max_young_cset;
93
117
size_t min_garbage = (free_target > actual_free) ? (free_target - actual_free) : 0 ;
94
118
@@ -101,31 +125,50 @@ void ShenandoahGlobalHeuristics::choose_global_collection_set(ShenandoahCollecti
101
125
for (size_t idx = 0 ; idx < size; idx++) {
102
126
ShenandoahHeapRegion* r = data[idx]._region ;
103
127
if (cset->is_preselected (r->index ())) {
128
+ fatal (" There should be no preselected regions during GLOBAL GC" );
104
129
continue ;
105
130
}
106
131
bool add_region = false ;
107
- if (r->is_old ()) {
132
+ if (r->is_old () || (r-> age () >= tenuring_threshold) ) {
108
133
size_t new_cset = old_cur_cset + r->get_live_data_bytes ();
134
+ if ((r->garbage () > garbage_threshold)) {
135
+ while ((new_cset > max_old_cset) && (unaffiliated_young_regions > 0 )) {
136
+ unaffiliated_young_regions--;
137
+ regions_transferred_to_old++;
138
+ max_old_cset += region_size_bytes / ShenandoahOldEvacWaste;
139
+ }
140
+ }
109
141
if ((new_cset <= max_old_cset) && (r->garbage () > garbage_threshold)) {
110
142
add_region = true ;
111
143
old_cur_cset = new_cset;
112
144
}
113
- } else if (r->age () < tenuring_threshold) {
145
+ } else {
146
+ assert (r->is_young () && (r->age () < tenuring_threshold), " DeMorgan's law (assuming r->is_affiliated)" );
114
147
size_t new_cset = young_cur_cset + r->get_live_data_bytes ();
115
148
size_t region_garbage = r->garbage ();
116
149
size_t new_garbage = cur_young_garbage + region_garbage;
117
150
bool add_regardless = (region_garbage > ignore_threshold) && (new_garbage < min_garbage);
151
+
152
+ if (add_regardless || (r->garbage () > garbage_threshold)) {
153
+ while ((new_cset > max_young_cset) && (unaffiliated_young_regions > 0 )) {
154
+ unaffiliated_young_regions--;
155
+ max_young_cset += region_size_bytes / ShenandoahEvacWaste;
156
+ }
157
+ }
118
158
if ((new_cset <= max_young_cset) && (add_regardless || (region_garbage > garbage_threshold))) {
119
159
add_region = true ;
120
160
young_cur_cset = new_cset;
121
161
cur_young_garbage = new_garbage;
122
162
}
123
163
}
124
- // Note that we do not add aged regions if they were not pre-selected. The reason they were not preselected
125
- // is because there is not sufficient room in old-gen to hold their to-be-promoted live objects.
126
-
127
164
if (add_region) {
128
165
cset->add_region (r);
129
166
}
130
167
}
168
+
169
+ if (regions_transferred_to_old > 0 ) {
170
+ heap->generation_sizer ()->force_transfer_to_old (regions_transferred_to_old);
171
+ heap->set_young_evac_reserve (heap->get_young_evac_reserve () - regions_transferred_to_old * region_size_bytes);
172
+ heap->set_old_evac_reserve (heap->get_old_evac_reserve () + regions_transferred_to_old * region_size_bytes);
173
+ }
131
174
}
0 commit comments