8303252: G1: Return early from Full-GC if no regions are selected for compaction.

Reviewed-by: tschatzl, ayang
This commit is contained in:
Ivan Walulya 2023-03-01 13:52:21 +00:00
parent 8b86e1ee11
commit c1e77e0564
9 changed files with 222 additions and 128 deletions

@ -34,6 +34,7 @@
#include "gc/g1/g1FullGCMarker.inline.hpp"
#include "gc/g1/g1FullGCMarkTask.hpp"
#include "gc/g1/g1FullGCPrepareTask.inline.hpp"
#include "gc/g1/g1FullGCResetMetadataTask.hpp"
#include "gc/g1/g1FullGCScope.hpp"
#include "gc/g1/g1OopClosures.hpp"
#include "gc/g1/g1Policy.hpp"
@ -117,6 +118,7 @@ G1FullCollector::G1FullCollector(G1CollectedHeap* heap,
_heap(heap),
_scope(heap->monitoring_support(), explicit_gc, clear_soft_refs, do_maximal_compaction, tracer),
_num_workers(calc_active_workers()),
_has_compaction_targets(false),
_oop_queue_set(_num_workers),
_array_queue_set(_num_workers),
_preserved_marks_set(true),
@ -207,9 +209,17 @@ void G1FullCollector::collect() {
phase2_prepare_compaction();
phase3_adjust_pointers();
if (has_compaction_targets()) {
phase3_adjust_pointers();
phase4_do_compaction();
phase4_do_compaction();
} else {
// All regions have a high live ratio thus will not be compacted.
// The live ratio is only considered if do_maximal_compaction is false.
log_info(gc, phases) ("No Regions selected for compaction. Skipping Phase 3: Adjust pointers and Phase 4: Compact heap");
}
phase5_reset_metadata();
G1CollectedHeap::finish_codecache_marking_cycle();
}
@ -322,6 +332,10 @@ void G1FullCollector::phase2_prepare_compaction() {
phase2a_determine_worklists();
if (!has_compaction_targets()) {
return;
}
bool has_free_compaction_targets = phase2b_forward_oops();
// Try to avoid OOM immediately after Full GC in case there are no free regions
@ -357,11 +371,6 @@ uint G1FullCollector::truncate_parallel_cps() {
}
}
if (lowest_current == (uint)-1) {
// worker compaction points are empty
return lowest_current;
}
for (uint i = 0; i < workers(); i++) {
G1FullGCCompactionPoint* cp = compaction_point(i);
if (cp->has_regions()) {
@ -386,9 +395,7 @@ void G1FullCollector::phase2c_prepare_serial_compaction() {
// lowest and the highest region in the tails of the compaction points.
uint start_serial = truncate_parallel_cps();
if (start_serial >= _heap->max_reserved_regions()) {
return;
}
assert(start_serial < _heap->max_reserved_regions(), "Called on empty parallel compaction queues");
G1FullGCCompactionPoint* serial_cp = serial_compaction_point();
assert(!serial_cp->is_initialized(), "sanity!");
@ -431,6 +438,13 @@ void G1FullCollector::phase4_do_compaction() {
}
}
void G1FullCollector::phase5_reset_metadata() {
// Clear region metadata that is invalid after GC for all regions.
GCTraceTime(Info, gc, phases) info("Phase 5: Reset Metadata", scope()->timer());
G1FullGCResetMetadataTask task(this);
run_task(&task);
}
void G1FullCollector::restore_marks() {
_preserved_marks_set.restore(_heap->workers());
_preserved_marks_set.reclaim();

@ -75,6 +75,7 @@ class G1FullCollector : StackObj {
G1CollectedHeap* _heap;
G1FullGCScope _scope;
uint _num_workers;
bool _has_compaction_targets;
G1FullGCMarker** _markers;
G1FullGCCompactionPoint** _compaction_points;
OopQueueSet _oop_queue_set;
@ -137,6 +138,9 @@ public:
inline void set_compaction_top(HeapRegion* r, HeapWord* value);
inline HeapWord* compaction_top(HeapRegion* r) const;
inline void set_has_compaction_targets();
inline bool has_compaction_targets() const;
uint truncate_parallel_cps();
private:
@ -149,6 +153,7 @@ private:
void phase3_adjust_pointers();
void phase4_do_compaction();
void phase5_reset_metadata();
void restore_marks();
void verify_after_marking();

@ -1,5 +1,5 @@
/*
* Copyright (c) 2020, 2022, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2020, 2023, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@ -69,5 +69,15 @@ HeapWord* G1FullCollector::compaction_top(HeapRegion* r) const {
return Atomic::load(&_compaction_tops[r->hrm_index()]);
}
void G1FullCollector::set_has_compaction_targets() {
if (!_has_compaction_targets) {
_has_compaction_targets = true;
}
}
bool G1FullCollector::has_compaction_targets() const {
return _has_compaction_targets;
}
#endif // SHARE_GC_G1_G1FULLCOLLECTOR_INLINE_HPP

@ -1,5 +1,5 @@
/*
* Copyright (c) 2017, 2022, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2017, 2023, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@ -34,43 +34,6 @@
#include "oops/oop.inline.hpp"
#include "utilities/ticks.hpp"
// Do work for all skip-compacting regions.
class G1ResetSkipCompactingClosure : public HeapRegionClosure {
G1FullCollector* _collector;
public:
G1ResetSkipCompactingClosure(G1FullCollector* collector) : _collector(collector) { }
bool do_heap_region(HeapRegion* r) {
uint region_index = r->hrm_index();
// Only for skip-compaction regions; early return otherwise.
if (!_collector->is_skip_compacting(region_index)) {
return false;
}
#ifdef ASSERT
if (r->is_humongous()) {
oop obj = cast_to_oop(r->humongous_start_region()->bottom());
assert(_collector->mark_bitmap()->is_marked(obj), "must be live");
} else if (r->is_open_archive()) {
bool is_empty = (_collector->live_words(r->hrm_index()) == 0);
assert(!is_empty, "should contain at least one live obj");
} else if (r->is_closed_archive()) {
// should early-return above
ShouldNotReachHere();
} else {
assert(_collector->live_words(region_index) > _collector->scope()->region_compaction_threshold(),
"should be quite full");
}
#endif
assert(_collector->compaction_top(r) == nullptr,
"region %u compaction_top " PTR_FORMAT " must not be different from bottom " PTR_FORMAT,
r->hrm_index(), p2i(_collector->compaction_top(r)), p2i(r->bottom()));
r->reset_skip_compacting_after_full_gc();
return false;
}
};
void G1FullGCCompactTask::G1CompactRegionClosure::clear_in_bitmap(oop obj) {
assert(_bitmap->is_marked(obj), "Should only compact marked objects");
_bitmap->clear(obj);
@ -124,10 +87,6 @@ void G1FullGCCompactTask::work(uint worker_id) {
++it) {
compact_region(*it);
}
G1ResetSkipCompactingClosure hc(collector());
G1CollectedHeap::heap()->heap_region_par_iterate_from_worker_offset(&hc, &_claimer, worker_id);
log_task("Compaction task", worker_id, start);
}
void G1FullGCCompactTask::serial_compaction() {

@ -1,5 +1,5 @@
/*
* Copyright (c) 2017, 2022, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2017, 2023, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@ -95,12 +95,6 @@ void G1FullGCPrepareTask::work(uint worker_id) {
set_has_free_compaction_targets();
}
}
// Clear region metadata that is invalid after GC for all regions.
{
G1ResetMetadataClosure closure(collector());
G1CollectedHeap::heap()->heap_region_par_iterate_from_start(&closure, &_hrclaimer);
}
log_task("Prepare compaction task", worker_id, start);
}
@ -111,30 +105,6 @@ G1FullGCPrepareTask::G1CalculatePointersClosure::G1CalculatePointersClosure(G1Fu
_bitmap(collector->mark_bitmap()),
_cp(cp) { }
G1FullGCPrepareTask::G1ResetMetadataClosure::G1ResetMetadataClosure(G1FullCollector* collector) :
_g1h(G1CollectedHeap::heap()),
_collector(collector) { }
void G1FullGCPrepareTask::G1ResetMetadataClosure::reset_region_metadata(HeapRegion* hr) {
hr->rem_set()->clear();
hr->clear_cardtable();
}
bool G1FullGCPrepareTask::G1ResetMetadataClosure::do_heap_region(HeapRegion* hr) {
uint const region_idx = hr->hrm_index();
if (!_collector->is_compaction_target(region_idx)) {
assert(!hr->is_free(), "all free regions should be compaction targets");
assert(_collector->is_skip_compacting(region_idx) || hr->is_closed_archive(), "must be");
if (hr->needs_scrubbing_during_full_gc()) {
scrub_skip_compacting_region(hr, hr->is_young());
}
}
// Reset data structures not valid after Full GC.
reset_region_metadata(hr);
return false;
}
G1FullGCPrepareTask::G1PrepareCompactLiveClosure::G1PrepareCompactLiveClosure(G1FullGCCompactionPoint* cp) :
_cp(cp) { }
@ -151,31 +121,3 @@ void G1FullGCPrepareTask::G1CalculatePointersClosure::prepare_for_compaction(Hea
hr->apply_to_marked_objects(_bitmap, &prepare_compact);
}
}
void G1FullGCPrepareTask::G1ResetMetadataClosure::scrub_skip_compacting_region(HeapRegion* hr, bool update_bot_for_live) {
assert(hr->needs_scrubbing_during_full_gc(), "must be");
HeapWord* limit = hr->top();
HeapWord* current_obj = hr->bottom();
G1CMBitMap* bitmap = _collector->mark_bitmap();
while (current_obj < limit) {
if (bitmap->is_marked(current_obj)) {
oop current = cast_to_oop(current_obj);
size_t size = current->size();
if (update_bot_for_live) {
hr->update_bot_for_block(current_obj, current_obj + size);
}
current_obj += size;
continue;
}
// Found dead object, which is potentially unloaded, scrub to next
// marked object.
HeapWord* scrub_start = current_obj;
HeapWord* scrub_end = bitmap->get_next_marked_addr(scrub_start, limit);
assert(scrub_start != scrub_end, "must advance");
hr->fill_range_with_dead_objects(scrub_start, scrub_end);
current_obj = scrub_end;
}
}

@ -90,22 +90,6 @@ private:
bool do_heap_region(HeapRegion* hr);
};
class G1ResetMetadataClosure : public HeapRegionClosure {
G1CollectedHeap* _g1h;
G1FullCollector* _collector;
void reset_region_metadata(HeapRegion* hr);
// Scrub all runs of dead objects within the given region by putting filler
// objects and updating the corresponding BOT. If update_bot_for_live is true,
// also update the BOT for live objects.
void scrub_skip_compacting_region(HeapRegion* hr, bool update_bot_for_live);
public:
G1ResetMetadataClosure(G1FullCollector* collector);
bool do_heap_region(HeapRegion* hr);
};
class G1PrepareCompactLiveClosure : public StackObj {
G1FullGCCompactionPoint* _cp;

@ -68,6 +68,8 @@ inline G1FullGCCompactionPoint* G1DetermineCompactionQueueClosure::next_compacti
inline void G1DetermineCompactionQueueClosure::add_to_compaction_queue(HeapRegion* hr) {
_collector->set_compaction_top(hr, hr->bottom());
_collector->set_has_compaction_targets();
G1FullGCCompactionPoint* cp = next_compaction_point();
if (!cp->is_initialized()) {
cp->initialize(hr);

@ -0,0 +1,117 @@
/*
* Copyright (c) 2023, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*
*/
#include "precompiled.hpp"
#include "gc/g1/g1FullCollector.inline.hpp"
#include "gc/g1/g1FullGCResetMetadataTask.hpp"
#include "utilities/ticks.hpp"
G1FullGCResetMetadataTask::G1ResetMetadataClosure::G1ResetMetadataClosure(G1FullCollector* collector) :
_g1h(G1CollectedHeap::heap()),
_collector(collector) { }
void G1FullGCResetMetadataTask::G1ResetMetadataClosure::reset_region_metadata(HeapRegion* hr) {
hr->rem_set()->clear();
hr->clear_cardtable();
}
bool G1FullGCResetMetadataTask::G1ResetMetadataClosure::do_heap_region(HeapRegion* hr) {
uint const region_idx = hr->hrm_index();
if (!_collector->is_compaction_target(region_idx)) {
assert(!hr->is_free(), "all free regions should be compaction targets");
assert(_collector->is_skip_compacting(region_idx) || hr->is_closed_archive(), "must be");
if (hr->needs_scrubbing_during_full_gc()) {
scrub_skip_compacting_region(hr, hr->is_young());
}
if (_collector->is_skip_compacting(region_idx)) {
reset_skip_compacting(hr);
}
}
// Reset data structures not valid after Full GC.
reset_region_metadata(hr);
return false;
}
void G1FullGCResetMetadataTask::G1ResetMetadataClosure::scrub_skip_compacting_region(HeapRegion* hr, bool update_bot_for_live) {
assert(hr->needs_scrubbing_during_full_gc(), "must be");
HeapWord* limit = hr->top();
HeapWord* current_obj = hr->bottom();
G1CMBitMap* bitmap = _collector->mark_bitmap();
while (current_obj < limit) {
if (bitmap->is_marked(current_obj)) {
oop current = cast_to_oop(current_obj);
size_t size = current->size();
if (update_bot_for_live) {
hr->update_bot_for_block(current_obj, current_obj + size);
}
current_obj += size;
continue;
}
// Found dead object, which is potentially unloaded, scrub to next
// marked object.
HeapWord* scrub_start = current_obj;
HeapWord* scrub_end = bitmap->get_next_marked_addr(scrub_start, limit);
assert(scrub_start != scrub_end, "must advance");
hr->fill_range_with_dead_objects(scrub_start, scrub_end);
current_obj = scrub_end;
}
}
void G1FullGCResetMetadataTask::G1ResetMetadataClosure::reset_skip_compacting(HeapRegion* hr) {
#ifdef ASSERT
uint region_index = hr->hrm_index();
assert(_collector->is_skip_compacting(region_index), "Only call on is_skip_compacting regions");
if (hr->is_humongous()) {
oop obj = cast_to_oop(hr->humongous_start_region()->bottom());
assert(_collector->mark_bitmap()->is_marked(obj), "must be live");
} else if (hr->is_open_archive()) {
bool is_empty = (_collector->live_words(hr->hrm_index()) == 0);
assert(!is_empty, "should contain at least one live obj");
} else if (hr->is_closed_archive()) {
// should early-return above
ShouldNotReachHere();
} else {
assert(_collector->live_words(region_index) > _collector->scope()->region_compaction_threshold(),
"should be quite full");
}
assert(_collector->compaction_top(hr) == nullptr,
"region %u compaction_top " PTR_FORMAT " must not be different from bottom " PTR_FORMAT,
hr->hrm_index(), p2i(_collector->compaction_top(hr)), p2i(hr->bottom()));
#endif
hr->reset_skip_compacting_after_full_gc();
}
void G1FullGCResetMetadataTask::work(uint worker_id) {
Ticks start = Ticks::now();
G1ResetMetadataClosure hc(collector());
G1CollectedHeap::heap()->heap_region_par_iterate_from_worker_offset(&hc, &_claimer, worker_id);
log_task("Reset Metadata task", worker_id, start);
}

@ -0,0 +1,61 @@
/*
* Copyright (c) 2023, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*
*/
#ifndef SHARE_GC_G1_G1FULLGCRESETMETADATATASK_HPP
#define SHARE_GC_G1_G1FULLGCRESETMETADATATASK_HPP
#include "gc/g1/g1FullGCTask.hpp"
#include "gc/g1/heapRegion.hpp"
class G1FullGCResetMetadataTask : public G1FullGCTask {
G1FullCollector* _collector;
HeapRegionClaimer _claimer;
class G1ResetMetadataClosure : public HeapRegionClosure {
G1CollectedHeap* _g1h;
G1FullCollector* _collector;
void reset_region_metadata(HeapRegion* hr);
// Scrub all runs of dead objects within the given region by putting filler
// objects and updating the corresponding BOT. If update_bot_for_live is true,
// also update the BOT for live objects.
void scrub_skip_compacting_region(HeapRegion* hr, bool update_bot_for_live);
void reset_skip_compacting(HeapRegion* r);
public:
G1ResetMetadataClosure(G1FullCollector* collector);
bool do_heap_region(HeapRegion* hr);
};
public:
G1FullGCResetMetadataTask(G1FullCollector* collector) :
G1FullGCTask("G1 Reset Metadata Task", collector),
_collector(collector),
_claimer(collector->workers()) { }
void work(uint worker_id);
};
#endif // SHARE_GC_G1_G1FULLGCRESETMETADATATASK_HPP