8337658: ZGC: Move soft reference handling out of the driver loop function

Reviewed-by: gli, aboldtch, eosterlund
This commit is contained in:
Stefan Karlsson 2024-08-23 07:09:40 +00:00
parent 8e0d0190ed
commit 9cbf685b0b
8 changed files with 47 additions and 31 deletions

View File

@ -230,8 +230,8 @@ void ZDriverMinor::terminate() {
_port.send_async(request);
}
static bool should_clear_soft_references(GCCause::Cause cause) {
// Clear soft references if implied by the GC cause
static bool should_clear_all_soft_references(GCCause::Cause cause) {
// Clear all soft references if implied by the GC cause
switch (cause) {
case GCCause::_wb_full_gc:
case GCCause::_metadata_GC_clear_soft_refs:
@ -259,12 +259,12 @@ static bool should_clear_soft_references(GCCause::Cause cause) {
break;
}
// Clear soft references if threads are stalled waiting for an old collection
// Clear all soft references if threads are stalled waiting for an old collection
if (ZHeap::heap()->is_alloc_stalling_for_old()) {
return true;
}
// Don't clear
// Don't clear all soft references
return false;
}
@ -302,13 +302,17 @@ static bool should_preclean_young(GCCause::Cause cause) {
return true;
}
// It is important that when soft references are cleared, we also pre-clean the young
// generation, as we might otherwise throw premature OOM. Therefore, all causes that
// trigger soft ref cleaning must also trigger pre-cleaning of young gen. If allocations
// stalled when checking for soft ref cleaning, then since we hold the driver locker all
// the way until we check for young gen pre-cleaning, we can be certain that we should
// We clear all soft references as a last-ditch effort to collect memory
// before throwing an OOM. Therefore it is important that when the GC policy
// is to clear all soft references, that we also pre-clean the young
// generation, as we might otherwise throw premature OOM.
//
// Therefore, all causes that trigger all soft ref clearing must also trigger
// pre-cleaning of young gen. If allocations stalled when checking for all
// soft ref clearing, then since we hold the driver locker all the way until
// we check for young gen pre-cleaning, we can be certain that we should
// catch that above and perform young gen pre-cleaning.
assert(!should_clear_soft_references(cause), "Clearing soft references without pre-cleaning young gen");
assert(!should_clear_all_soft_references(cause), "Clearing all soft references without pre-cleaning young gen");
return false;
}
@ -395,6 +399,10 @@ public:
// Select number of worker threads to use
ZGeneration::young()->set_active_workers(request.young_nworkers());
ZGeneration::old()->set_active_workers(request.old_nworkers());
// Set up soft reference policy
const bool clear_all = should_clear_all_soft_references(request.cause());
ZGeneration::old()->set_soft_reference_policy(clear_all);
}
~ZDriverScopeMajor() {
@ -444,12 +452,13 @@ void ZDriverMajor::gc(const ZDriverRequest& request) {
collect_old();
}
static void handle_alloc_stalling_for_old(bool cleared_soft_refs) {
ZHeap::heap()->handle_alloc_stalling_for_old(cleared_soft_refs);
static void handle_alloc_stalling_for_old() {
const bool cleared_all = ZGeneration::old()->uses_clear_all_soft_reference_policy();
ZHeap::heap()->handle_alloc_stalling_for_old(cleared_all);
}
void ZDriverMajor::handle_alloc_stalls(bool cleared_soft_refs) const {
handle_alloc_stalling_for_old(cleared_soft_refs);
void ZDriverMajor::handle_alloc_stalls() const {
handle_alloc_stalling_for_old();
}
void ZDriverMajor::run_thread() {
@ -464,10 +473,6 @@ void ZDriverMajor::run_thread() {
abortpoint();
// Set up soft reference policy
const bool clear_soft_refs = should_clear_soft_references(request.cause());
ZGeneration::old()->set_soft_reference_policy(clear_soft_refs);
// Run GC
gc(request);
@ -477,7 +482,7 @@ void ZDriverMajor::run_thread() {
_port.ack();
// Handle allocation stalls
handle_alloc_stalls(clear_soft_refs);
handle_alloc_stalls();
ZBreakpoint::at_after_gc();
}

View File

@ -112,7 +112,7 @@ private:
void collect_old();
void gc(const ZDriverRequest& request);
void handle_alloc_stalls(bool cleared_soft_refs) const;
void handle_alloc_stalls() const;
protected:
virtual void run_thread();

View File

@ -1286,6 +1286,10 @@ void ZGenerationOld::set_soft_reference_policy(bool clear) {
_reference_processor.set_soft_reference_policy(clear);
}
bool ZGenerationOld::uses_clear_all_soft_reference_policy() const {
return _reference_processor.uses_clear_all_soft_reference_policy();
}
class ZRendezvousHandshakeClosure : public HandshakeClosure {
public:
ZRendezvousHandshakeClosure()

View File

@ -309,6 +309,7 @@ public:
// Reference processing
ReferenceDiscoverer* reference_discoverer();
void set_soft_reference_policy(bool clear);
bool uses_clear_all_soft_reference_policy() const;
uint total_collections_at_start() const;

View File

@ -86,8 +86,8 @@ inline void ZHeap::handle_alloc_stalling_for_young() {
_page_allocator.handle_alloc_stalling_for_young();
}
inline void ZHeap::handle_alloc_stalling_for_old(bool cleared_soft_refs) {
_page_allocator.handle_alloc_stalling_for_old(cleared_soft_refs);
inline void ZHeap::handle_alloc_stalling_for_old(bool cleared_all_soft_refs) {
_page_allocator.handle_alloc_stalling_for_old(cleared_all_soft_refs);
}
inline bool ZHeap::is_oop(uintptr_t addr) const {

View File

@ -985,9 +985,9 @@ void ZPageAllocator::handle_alloc_stalling_for_young() {
restart_gc();
}
void ZPageAllocator::handle_alloc_stalling_for_old(bool cleared_soft_refs) {
void ZPageAllocator::handle_alloc_stalling_for_old(bool cleared_all_soft_refs) {
ZLocker<ZLock> locker(&_lock);
if (cleared_soft_refs) {
if (cleared_all_soft_refs) {
notify_out_of_memory();
}
restart_gc();

View File

@ -113,7 +113,7 @@ static void list_append(zaddress& head, zaddress& tail, zaddress reference) {
ZReferenceProcessor::ZReferenceProcessor(ZWorkers* workers)
: _workers(workers),
_soft_reference_policy(nullptr),
_clear_all_soft_refs(false),
_uses_clear_all_soft_reference_policy(false),
_encountered_count(),
_discovered_count(),
_enqueued_count(),
@ -121,13 +121,13 @@ ZReferenceProcessor::ZReferenceProcessor(ZWorkers* workers)
_pending_list(zaddress::null),
_pending_list_tail(zaddress::null) {}
void ZReferenceProcessor::set_soft_reference_policy(bool clear) {
void ZReferenceProcessor::set_soft_reference_policy(bool clear_all_soft_references) {
static AlwaysClearPolicy always_clear_policy;
static LRUMaxHeapPolicy lru_max_heap_policy;
_clear_all_soft_refs = clear;
_uses_clear_all_soft_reference_policy = clear_all_soft_references;
if (clear) {
if (clear_all_soft_references) {
_soft_reference_policy = &always_clear_policy;
} else {
_soft_reference_policy = &lru_max_heap_policy;
@ -136,6 +136,10 @@ void ZReferenceProcessor::set_soft_reference_policy(bool clear) {
_soft_reference_policy->setup();
}
bool ZReferenceProcessor::uses_clear_all_soft_reference_policy() const {
return _uses_clear_all_soft_reference_policy;
}
bool ZReferenceProcessor::is_inactive(zaddress reference, oop referent, ReferenceType type) const {
if (type == REF_FINAL) {
// A FinalReference is inactive if its next field is non-null. An application can't
@ -440,7 +444,7 @@ public:
void ZReferenceProcessor::process_references() {
ZStatTimerOld timer(ZSubPhaseConcurrentReferencesProcess);
if (_clear_all_soft_refs) {
if (_uses_clear_all_soft_reference_policy) {
log_info(gc, ref)("Clearing All SoftReferences");
}

View File

@ -41,7 +41,7 @@ private:
ZWorkers* const _workers;
ReferencePolicy* _soft_reference_policy;
bool _clear_all_soft_refs;
bool _uses_clear_all_soft_reference_policy;
ZPerWorker<Counters> _encountered_count;
ZPerWorker<Counters> _discovered_count;
ZPerWorker<Counters> _enqueued_count;
@ -69,7 +69,9 @@ private:
public:
ZReferenceProcessor(ZWorkers* workers);
void set_soft_reference_policy(bool clear);
void set_soft_reference_policy(bool clear_all_soft_references);
bool uses_clear_all_soft_reference_policy() const;
void reset_statistics();
virtual bool discover_reference(oop reference, ReferenceType type);