Skip to content

Commit 96889bf

Browse files
author
Ivan Walulya
committedMar 16, 2023
8191565: Last-ditch Full GC should also move humongous objects
Reviewed-by: tschatzl, sjohanss
1 parent f629152 commit 96889bf

15 files changed

+354
-79
lines changed
 

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

+82-60
Original file line numberDiff line numberDiff line change
@@ -193,80 +193,56 @@ HeapRegion* G1CollectedHeap::new_region(size_t word_size,
193193
return res;
194194
}
195195

196-
HeapWord*
197-
G1CollectedHeap::humongous_obj_allocate_initialize_regions(HeapRegion* first_hr,
198-
uint num_regions,
199-
size_t word_size) {
200-
assert(first_hr != NULL, "pre-condition");
201-
assert(is_humongous(word_size), "word_size should be humongous");
202-
assert(num_regions * HeapRegion::GrainWords >= word_size, "pre-condition");
203-
204-
// Index of last region in the series.
205-
uint first = first_hr->hrm_index();
206-
uint last = first + num_regions - 1;
207-
208-
// We need to initialize the region(s) we just discovered. This is
209-
// a bit tricky given that it can happen concurrently with
210-
// refinement threads refining cards on these regions and
211-
// potentially wanting to refine the BOT as they are scanning
212-
// those cards (this can happen shortly after a cleanup; see CR
213-
// 6991377). So we have to set up the region(s) carefully and in
214-
// a specific order.
215-
216-
// The word size sum of all the regions we will allocate.
217-
size_t word_size_sum = (size_t) num_regions * HeapRegion::GrainWords;
196+
void G1CollectedHeap::set_humongous_metadata(HeapRegion* first_hr,
197+
uint num_regions,
198+
size_t word_size,
199+
bool update_remsets) {
200+
// Calculate the new top of the humongous object.
201+
HeapWord* obj_top = first_hr->bottom() + word_size;
202+
// The word size sum of all the regions used
203+
size_t word_size_sum = num_regions * HeapRegion::GrainWords;
218204
assert(word_size <= word_size_sum, "sanity");
219205

220-
// The passed in hr will be the "starts humongous" region. The header
221-
// of the new object will be placed at the bottom of this region.
222-
HeapWord* new_obj = first_hr->bottom();
223-
// This will be the new top of the new object.
224-
HeapWord* obj_top = new_obj + word_size;
225-
226-
// First, we need to zero the header of the space that we will be
227-
// allocating. When we update top further down, some refinement
228-
// threads might try to scan the region. By zeroing the header we
229-
// ensure that any thread that will try to scan the region will
230-
// come across the zero klass word and bail out.
231-
//
232-
// NOTE: It would not have been correct to have used
233-
// CollectedHeap::fill_with_object() and make the space look like
234-
// an int array. The thread that is doing the allocation will
235-
// later update the object header to a potentially different array
236-
// type and, for a very short period of time, the klass and length
237-
// fields will be inconsistent. This could cause a refinement
238-
// thread to calculate the object size incorrectly.
239-
Copy::fill_to_words(new_obj, oopDesc::header_size(), 0);
206+
// How many words memory we "waste" which cannot hold a filler object.
207+
size_t words_not_fillable = 0;
240208

241-
// Next, pad out the unused tail of the last region with filler
209+
// Pad out the unused tail of the last region with filler
242210
// objects, for improved usage accounting.
243-
// How many words we use for filler objects.
244-
size_t word_fill_size = word_size_sum - word_size;
245211

246-
// How many words memory we "waste" which cannot hold a filler object.
247-
size_t words_not_fillable = 0;
212+
// How many words can we use for filler objects.
213+
size_t words_fillable = word_size_sum - word_size;
248214

249-
if (word_fill_size >= min_fill_size()) {
250-
fill_with_objects(obj_top, word_fill_size);
251-
} else if (word_fill_size > 0) {
215+
if (words_fillable >= G1CollectedHeap::min_fill_size()) {
216+
G1CollectedHeap::fill_with_objects(obj_top, words_fillable);
217+
} else {
252218
// We have space to fill, but we cannot fit an object there.
253-
words_not_fillable = word_fill_size;
254-
word_fill_size = 0;
219+
words_not_fillable = words_fillable;
220+
words_fillable = 0;
255221
}
256222

257223
// We will set up the first region as "starts humongous". This
258224
// will also update the BOT covering all the regions to reflect
259225
// that there is a single object that starts at the bottom of the
260226
// first region.
261-
first_hr->set_starts_humongous(obj_top, word_fill_size);
262-
_policy->remset_tracker()->update_at_allocate(first_hr);
263-
// Then, if there are any, we will set up the "continues
264-
// humongous" regions.
265-
HeapRegion* hr = NULL;
227+
first_hr->hr_clear(false /* clear_space */);
228+
first_hr->set_starts_humongous(obj_top, words_fillable);
229+
230+
if (update_remsets) {
231+
_policy->remset_tracker()->update_at_allocate(first_hr);
232+
}
233+
234+
// Indices of first and last regions in the series.
235+
uint first = first_hr->hrm_index();
236+
uint last = first + num_regions - 1;
237+
238+
HeapRegion* hr = nullptr;
266239
for (uint i = first + 1; i <= last; ++i) {
267240
hr = region_at(i);
241+
hr->hr_clear(false /* clear_space */);
268242
hr->set_continues_humongous(first_hr);
269-
_policy->remset_tracker()->update_at_allocate(hr);
243+
if (update_remsets) {
244+
_policy->remset_tracker()->update_at_allocate(hr);
245+
}
270246
}
271247

272248
// Up to this point no concurrent thread would have been able to
@@ -297,11 +273,57 @@ G1CollectedHeap::humongous_obj_allocate_initialize_regions(HeapRegion* first_hr,
297273
assert(words_not_fillable == 0 ||
298274
first_hr->bottom() + word_size_sum - words_not_fillable == hr->top(),
299275
"Miscalculation in humongous allocation");
276+
}
277+
278+
HeapWord*
279+
G1CollectedHeap::humongous_obj_allocate_initialize_regions(HeapRegion* first_hr,
280+
uint num_regions,
281+
size_t word_size) {
282+
assert(first_hr != NULL, "pre-condition");
283+
assert(is_humongous(word_size), "word_size should be humongous");
284+
assert(num_regions * HeapRegion::GrainWords >= word_size, "pre-condition");
285+
286+
// Index of last region in the series.
287+
uint first = first_hr->hrm_index();
288+
uint last = first + num_regions - 1;
289+
290+
// We need to initialize the region(s) we just discovered. This is
291+
// a bit tricky given that it can happen concurrently with
292+
// refinement threads refining cards on these regions and
293+
// potentially wanting to refine the BOT as they are scanning
294+
// those cards (this can happen shortly after a cleanup; see CR
295+
// 6991377). So we have to set up the region(s) carefully and in
296+
// a specific order.
300297

301-
increase_used((word_size_sum - words_not_fillable) * HeapWordSize);
298+
// The passed in hr will be the "starts humongous" region. The header
299+
// of the new object will be placed at the bottom of this region.
300+
HeapWord* new_obj = first_hr->bottom();
301+
302+
// First, we need to zero the header of the space that we will be
303+
// allocating. When we update top further down, some refinement
304+
// threads might try to scan the region. By zeroing the header we
305+
// ensure that any thread that will try to scan the region will
306+
// come across the zero klass word and bail out.
307+
//
308+
// NOTE: It would not have been correct to have used
309+
// CollectedHeap::fill_with_object() and make the space look like
310+
// an int array. The thread that is doing the allocation will
311+
// later update the object header to a potentially different array
312+
// type and, for a very short period of time, the klass and length
313+
// fields will be inconsistent. This could cause a refinement
314+
// thread to calculate the object size incorrectly.
315+
Copy::fill_to_words(new_obj, oopDesc::header_size(), 0);
316+
317+
// Next, update the metadata for the regions.
318+
set_humongous_metadata(first_hr, num_regions, word_size, true);
319+
320+
HeapRegion* last_hr = region_at(last);
321+
size_t used = byte_size(first_hr->bottom(), last_hr->top());
322+
323+
increase_used(used);
302324

303325
for (uint i = first; i <= last; ++i) {
304-
hr = region_at(i);
326+
HeapRegion *hr = region_at(i);
305327
_humongous_set.add(hr);
306328
_hr_printer.alloc(hr);
307329
}

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

+5
Original file line numberDiff line numberDiff line change
@@ -606,6 +606,11 @@ class G1CollectedHeap : public CollectedHeap {
606606
// Register the given region to be part of the collection set.
607607
inline void register_humongous_candidate_region_with_region_attr(uint index);
608608

609+
void set_humongous_metadata(HeapRegion* first_hr,
610+
uint num_regions,
611+
size_t word_size,
612+
bool update_remsets);
613+
609614
// We register a region with the fast "in collection set" test. We
610615
// simply set to true the array slot corresponding to this region.
611616
void register_young_region_with_region_attr(HeapRegion* r) {

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

+47-1
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@
4040
#include "gc/g1/g1Policy.hpp"
4141
#include "gc/g1/g1RegionMarkStatsCache.inline.hpp"
4242
#include "gc/shared/gcTraceTime.inline.hpp"
43-
#include "gc/shared/preservedMarks.hpp"
43+
#include "gc/shared/preservedMarks.inline.hpp"
4444
#include "gc/shared/referenceProcessor.hpp"
4545
#include "gc/shared/verifyOption.hpp"
4646
#include "gc/shared/weakProcessor.inline.hpp"
@@ -119,12 +119,15 @@ G1FullCollector::G1FullCollector(G1CollectedHeap* heap,
119119
_scope(heap->monitoring_support(), explicit_gc, clear_soft_refs, do_maximal_compaction, tracer),
120120
_num_workers(calc_active_workers()),
121121
_has_compaction_targets(false),
122+
_has_humongous(false),
122123
_oop_queue_set(_num_workers),
123124
_array_queue_set(_num_workers),
124125
_preserved_marks_set(true),
125126
_serial_compaction_point(this),
127+
_humongous_compaction_point(this),
126128
_is_alive(this, heap->concurrent_mark()->mark_bitmap()),
127129
_is_alive_mutator(heap->ref_processor_stw(), &_is_alive),
130+
_humongous_compaction_regions(8),
128131
_always_subject_to_discovery(),
129132
_is_subject_mutator(heap->ref_processor_stw(), &_always_subject_to_discovery),
130133
_region_attr_table() {
@@ -155,6 +158,7 @@ G1FullCollector::~G1FullCollector() {
155158
delete _markers[i];
156159
delete _compaction_points[i];
157160
}
161+
158162
FREE_C_HEAP_ARRAY(G1FullGCMarker*, _markers);
159163
FREE_C_HEAP_ARRAY(G1FullGCCompactionPoint*, _compaction_points);
160164
FREE_C_HEAP_ARRAY(HeapWord*, _compaction_tops);
@@ -246,6 +250,8 @@ void G1FullCollector::complete_collection() {
246250
_heap->gc_epilogue(true);
247251

248252
_heap->verify_after_full_collection();
253+
254+
_heap->print_heap_after_full_collection();
249255
}
250256

251257
void G1FullCollector::before_marking_update_attribute_table(HeapRegion* hr) {
@@ -343,6 +349,12 @@ void G1FullCollector::phase2_prepare_compaction() {
343349
// maximally compact the tail regions of the compaction queues serially.
344350
if (scope()->do_maximal_compaction() || !has_free_compaction_targets) {
345351
phase2c_prepare_serial_compaction();
352+
353+
if (scope()->do_maximal_compaction() &&
354+
has_humongous() &&
355+
serial_compaction_point()->has_regions()) {
356+
phase2d_prepare_humongous_compaction();
357+
}
346358
}
347359
}
348360

@@ -418,6 +430,35 @@ void G1FullCollector::phase2c_prepare_serial_compaction() {
418430
serial_cp->update();
419431
}
420432

433+
void G1FullCollector::phase2d_prepare_humongous_compaction() {
434+
GCTraceTime(Debug, gc, phases) debug("Phase 2: Prepare humongous compaction", scope()->timer());
435+
G1FullGCCompactionPoint* serial_cp = serial_compaction_point();
436+
assert(serial_cp->has_regions(), "Sanity!" );
437+
438+
uint last_serial_target = serial_cp->current_region()->hrm_index();
439+
uint region_index = last_serial_target + 1;
440+
uint max_reserved_regions = _heap->max_reserved_regions();
441+
442+
G1FullGCCompactionPoint* humongous_cp = humongous_compaction_point();
443+
444+
while (region_index < max_reserved_regions) {
445+
HeapRegion* hr = _heap->region_at_or_null(region_index);
446+
447+
if (hr == nullptr) {
448+
region_index++;
449+
continue;
450+
} else if (hr->is_starts_humongous()) {
451+
uint num_regions = humongous_cp->forward_humongous(hr);
452+
region_index += num_regions; // Skip over the continues humongous regions.
453+
continue;
454+
} else if (is_compaction_target(region_index)) {
455+
// Add the region to the humongous compaction point.
456+
humongous_cp->add(hr);
457+
}
458+
region_index++;
459+
}
460+
}
461+
421462
void G1FullCollector::phase3_adjust_pointers() {
422463
// Adjust the pointers to reflect the new locations
423464
GCTraceTime(Info, gc, phases) info("Phase 3: Adjust pointers", scope()->timer());
@@ -436,6 +477,11 @@ void G1FullCollector::phase4_do_compaction() {
436477
if (serial_compaction_point()->has_regions()) {
437478
task.serial_compaction();
438479
}
480+
481+
if (!_humongous_compaction_regions.is_empty()) {
482+
assert(scope()->do_maximal_compaction(), "Only compact humongous during maximal compaction");
483+
task.humongous_compaction();
484+
}
439485
}
440486

441487
void G1FullCollector::phase5_reset_metadata() {

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

+12
Original file line numberDiff line numberDiff line change
@@ -76,15 +76,18 @@ class G1FullCollector : StackObj {
7676
G1FullGCScope _scope;
7777
uint _num_workers;
7878
bool _has_compaction_targets;
79+
bool _has_humongous;
7980
G1FullGCMarker** _markers;
8081
G1FullGCCompactionPoint** _compaction_points;
8182
OopQueueSet _oop_queue_set;
8283
ObjArrayTaskQueueSet _array_queue_set;
8384
PreservedMarksSet _preserved_marks_set;
8485
G1FullGCCompactionPoint _serial_compaction_point;
86+
G1FullGCCompactionPoint _humongous_compaction_point;
8587
G1IsAliveClosure _is_alive;
8688
ReferenceProcessorIsAliveMutator _is_alive_mutator;
8789
G1RegionMarkStats* _live_stats;
90+
GrowableArrayCHeap<HeapRegion*, mtGC> _humongous_compaction_regions;
8891

8992
static uint calc_active_workers();
9093

@@ -115,6 +118,7 @@ class G1FullCollector : StackObj {
115118
ObjArrayTaskQueueSet* array_queue_set() { return &_array_queue_set; }
116119
PreservedMarksSet* preserved_mark_set() { return &_preserved_marks_set; }
117120
G1FullGCCompactionPoint* serial_compaction_point() { return &_serial_compaction_point; }
121+
G1FullGCCompactionPoint* humongous_compaction_point() { return &_humongous_compaction_point; }
118122
G1CMBitMap* mark_bitmap();
119123
ReferenceProcessor* reference_processor();
120124
size_t live_words(uint region_index) const {
@@ -134,22 +138,30 @@ class G1FullCollector : StackObj {
134138
inline void set_free(uint region_idx);
135139
inline bool is_free(uint region_idx) const;
136140
inline void update_from_compacting_to_skip_compacting(uint region_idx);
141+
inline void update_from_skip_compacting_to_compacting(uint region_idx);
137142

138143
inline void set_compaction_top(HeapRegion* r, HeapWord* value);
139144
inline HeapWord* compaction_top(HeapRegion* r) const;
140145

141146
inline void set_has_compaction_targets();
142147
inline bool has_compaction_targets() const;
143148

149+
inline void add_humongous_region(HeapRegion* hr);
150+
inline GrowableArrayCHeap<HeapRegion*, mtGC>& humongous_compaction_regions();
151+
144152
uint truncate_parallel_cps();
145153

154+
inline void set_has_humongous();
155+
inline bool has_humongous();
156+
146157
private:
147158
void phase1_mark_live_objects();
148159
void phase2_prepare_compaction();
149160

150161
void phase2a_determine_worklists();
151162
bool phase2b_forward_oops();
152163
void phase2c_prepare_serial_compaction();
164+
void phase2d_prepare_humongous_compaction();
153165

154166
void phase3_adjust_pointers();
155167
void phase4_do_compaction();

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

+23
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,11 @@ void G1FullCollector::update_from_compacting_to_skip_compacting(uint region_idx)
6161
_region_attr_table.set_skip_compacting(region_idx);
6262
}
6363

64+
void G1FullCollector::update_from_skip_compacting_to_compacting(uint region_idx) {
65+
DEBUG_ONLY(_region_attr_table.verify_is_skip_compacting(region_idx);)
66+
_region_attr_table.set_compacting(region_idx);
67+
}
68+
6469
void G1FullCollector::set_compaction_top(HeapRegion* r, HeapWord* value) {
6570
Atomic::store(&_compaction_tops[r->hrm_index()], value);
6671
}
@@ -79,5 +84,23 @@ bool G1FullCollector::has_compaction_targets() const {
7984
return _has_compaction_targets;
8085
}
8186

87+
void G1FullCollector::set_has_humongous() {
88+
if (!_has_humongous) {
89+
_has_humongous = true;
90+
}
91+
}
92+
93+
bool G1FullCollector::has_humongous() {
94+
return _has_humongous;
95+
}
96+
97+
void G1FullCollector::add_humongous_region(HeapRegion* hr) {
98+
_humongous_compaction_regions.append(hr);
99+
}
100+
101+
GrowableArrayCHeap<HeapRegion*, mtGC>& G1FullCollector::humongous_compaction_regions() {
102+
return _humongous_compaction_regions;
103+
}
104+
82105
#endif // SHARE_GC_G1_G1FULLCOLLECTOR_INLINE_HPP
83106

1 commit comments

Comments
 (1)

openjdk-notifier[bot] commented on Mar 16, 2023

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