Path: blob/master/src/hotspot/share/gc/z/zDriver.cpp
66644 views
/*1* Copyright (c) 2015, 2021, Oracle and/or its affiliates. All rights reserved.2* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.3*4* This code is free software; you can redistribute it and/or modify it5* under the terms of the GNU General Public License version 2 only, as6* published by the Free Software Foundation.7*8* This code is distributed in the hope that it will be useful, but WITHOUT9* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or10* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License11* version 2 for more details (a copy is included in the LICENSE file that12* accompanied this code).13*14* You should have received a copy of the GNU General Public License version15* 2 along with this work; if not, write to the Free Software Foundation,16* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.17*18* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA19* or visit www.oracle.com if you need additional information or have any20* questions.21*/2223#include "precompiled.hpp"24#include "gc/shared/gcId.hpp"25#include "gc/shared/gcLocker.hpp"26#include "gc/shared/gcVMOperations.hpp"27#include "gc/shared/isGCActiveMark.hpp"28#include "gc/z/zAbort.inline.hpp"29#include "gc/z/zBreakpoint.hpp"30#include "gc/z/zCollectedHeap.hpp"31#include "gc/z/zDriver.hpp"32#include "gc/z/zHeap.inline.hpp"33#include "gc/z/zMessagePort.inline.hpp"34#include "gc/z/zServiceability.hpp"35#include "gc/z/zStat.hpp"36#include "gc/z/zVerify.hpp"37#include "logging/log.hpp"38#include "memory/universe.hpp"39#include "runtime/vmOperations.hpp"40#include "runtime/vmThread.hpp"4142static const ZStatPhaseCycle ZPhaseCycle("Garbage Collection Cycle");43static const ZStatPhasePause ZPhasePauseMarkStart("Pause Mark Start");44static const ZStatPhaseConcurrent ZPhaseConcurrentMark("Concurrent Mark");45static const ZStatPhaseConcurrent ZPhaseConcurrentMarkContinue("Concurrent Mark Continue");46static const ZStatPhaseConcurrent ZPhaseConcurrentMarkFree("Concurrent Mark Free");47static const ZStatPhasePause ZPhasePauseMarkEnd("Pause Mark End");48static const ZStatPhaseConcurrent ZPhaseConcurrentProcessNonStrongReferences("Concurrent Process Non-Strong References");49static const ZStatPhaseConcurrent ZPhaseConcurrentResetRelocationSet("Concurrent Reset Relocation Set");50static const ZStatPhaseConcurrent ZPhaseConcurrentSelectRelocationSet("Concurrent Select Relocation Set");51static const ZStatPhasePause ZPhasePauseRelocateStart("Pause Relocate Start");52static const ZStatPhaseConcurrent ZPhaseConcurrentRelocated("Concurrent Relocate");53static const ZStatCriticalPhase ZCriticalPhaseGCLockerStall("GC Locker Stall", false /* verbose */);54static const ZStatSampler ZSamplerJavaThreads("System", "Java Threads", ZStatUnitThreads);5556ZDriverRequest::ZDriverRequest() :57ZDriverRequest(GCCause::_no_gc) {}5859ZDriverRequest::ZDriverRequest(GCCause::Cause cause) :60ZDriverRequest(cause, ConcGCThreads) {}6162ZDriverRequest::ZDriverRequest(GCCause::Cause cause, uint nworkers) :63_cause(cause),64_nworkers(nworkers) {}6566bool ZDriverRequest::operator==(const ZDriverRequest& other) const {67return _cause == other._cause;68}6970GCCause::Cause ZDriverRequest::cause() const {71return _cause;72}7374uint ZDriverRequest::nworkers() const {75return _nworkers;76}7778class VM_ZOperation : public VM_Operation {79private:80const uint _gc_id;81bool _gc_locked;82bool _success;8384public:85VM_ZOperation() :86_gc_id(GCId::current()),87_gc_locked(false),88_success(false) {}8990virtual bool needs_inactive_gc_locker() const {91// An inactive GC locker is needed in operations where we change the bad92// mask or move objects. Changing the bad mask will invalidate all oops,93// which makes it conceptually the same thing as moving all objects.94return false;95}9697virtual bool skip_thread_oop_barriers() const {98return true;99}100101virtual bool do_operation() = 0;102103virtual bool doit_prologue() {104Heap_lock->lock();105return true;106}107108virtual void doit() {109// Abort if GC locker state is incompatible110if (needs_inactive_gc_locker() && GCLocker::check_active_before_gc()) {111_gc_locked = true;112return;113}114115// Setup GC id and active marker116GCIdMark gc_id_mark(_gc_id);117IsGCActiveMark gc_active_mark;118119// Verify before operation120ZVerify::before_zoperation();121122// Execute operation123_success = do_operation();124125// Update statistics126ZStatSample(ZSamplerJavaThreads, Threads::number_of_threads());127}128129virtual void doit_epilogue() {130Heap_lock->unlock();131}132133bool gc_locked() const {134return _gc_locked;135}136137bool success() const {138return _success;139}140};141142class VM_ZMarkStart : public VM_ZOperation {143public:144virtual VMOp_Type type() const {145return VMOp_ZMarkStart;146}147148virtual bool needs_inactive_gc_locker() const {149return true;150}151152virtual bool do_operation() {153ZStatTimer timer(ZPhasePauseMarkStart);154ZServiceabilityPauseTracer tracer;155156ZCollectedHeap::heap()->increment_total_collections(true /* full */);157158ZHeap::heap()->mark_start();159return true;160}161};162163class VM_ZMarkEnd : public VM_ZOperation {164public:165virtual VMOp_Type type() const {166return VMOp_ZMarkEnd;167}168169virtual bool do_operation() {170ZStatTimer timer(ZPhasePauseMarkEnd);171ZServiceabilityPauseTracer tracer;172return ZHeap::heap()->mark_end();173}174};175176class VM_ZRelocateStart : public VM_ZOperation {177public:178virtual VMOp_Type type() const {179return VMOp_ZRelocateStart;180}181182virtual bool needs_inactive_gc_locker() const {183return true;184}185186virtual bool do_operation() {187ZStatTimer timer(ZPhasePauseRelocateStart);188ZServiceabilityPauseTracer tracer;189ZHeap::heap()->relocate_start();190return true;191}192};193194class VM_ZVerify : public VM_Operation {195public:196virtual VMOp_Type type() const {197return VMOp_ZVerify;198}199200virtual bool skip_thread_oop_barriers() const {201return true;202}203204virtual void doit() {205ZVerify::after_weak_processing();206}207};208209ZDriver::ZDriver() :210_gc_cycle_port(),211_gc_locker_port() {212set_name("ZDriver");213create_and_start();214}215216bool ZDriver::is_busy() const {217return _gc_cycle_port.is_busy();218}219220void ZDriver::collect(const ZDriverRequest& request) {221switch (request.cause()) {222case GCCause::_wb_young_gc:223case GCCause::_wb_conc_mark:224case GCCause::_wb_full_gc:225case GCCause::_dcmd_gc_run:226case GCCause::_java_lang_system_gc:227case GCCause::_full_gc_alot:228case GCCause::_scavenge_alot:229case GCCause::_jvmti_force_gc:230case GCCause::_metadata_GC_clear_soft_refs:231// Start synchronous GC232_gc_cycle_port.send_sync(request);233break;234235case GCCause::_z_timer:236case GCCause::_z_warmup:237case GCCause::_z_allocation_rate:238case GCCause::_z_allocation_stall:239case GCCause::_z_proactive:240case GCCause::_z_high_usage:241case GCCause::_metadata_GC_threshold:242// Start asynchronous GC243_gc_cycle_port.send_async(request);244break;245246case GCCause::_gc_locker:247// Restart VM operation previously blocked by the GC locker248_gc_locker_port.signal();249break;250251case GCCause::_wb_breakpoint:252ZBreakpoint::start_gc();253_gc_cycle_port.send_async(request);254break;255256default:257// Other causes not supported258fatal("Unsupported GC cause (%s)", GCCause::to_string(request.cause()));259break;260}261}262263template <typename T>264bool ZDriver::pause() {265for (;;) {266T op;267VMThread::execute(&op);268if (op.gc_locked()) {269// Wait for GC to become unlocked and restart the VM operation270ZStatTimer timer(ZCriticalPhaseGCLockerStall);271_gc_locker_port.wait();272continue;273}274275// Notify VM operation completed276_gc_locker_port.ack();277278return op.success();279}280}281282void ZDriver::pause_mark_start() {283pause<VM_ZMarkStart>();284}285286void ZDriver::concurrent_mark() {287ZStatTimer timer(ZPhaseConcurrentMark);288ZBreakpoint::at_after_marking_started();289ZHeap::heap()->mark(true /* initial */);290ZBreakpoint::at_before_marking_completed();291}292293bool ZDriver::pause_mark_end() {294return pause<VM_ZMarkEnd>();295}296297void ZDriver::concurrent_mark_continue() {298ZStatTimer timer(ZPhaseConcurrentMarkContinue);299ZHeap::heap()->mark(false /* initial */);300}301302void ZDriver::concurrent_mark_free() {303ZStatTimer timer(ZPhaseConcurrentMarkFree);304ZHeap::heap()->mark_free();305}306307void ZDriver::concurrent_process_non_strong_references() {308ZStatTimer timer(ZPhaseConcurrentProcessNonStrongReferences);309ZBreakpoint::at_after_reference_processing_started();310ZHeap::heap()->process_non_strong_references();311}312313void ZDriver::concurrent_reset_relocation_set() {314ZStatTimer timer(ZPhaseConcurrentResetRelocationSet);315ZHeap::heap()->reset_relocation_set();316}317318void ZDriver::pause_verify() {319if (VerifyBeforeGC || VerifyDuringGC || VerifyAfterGC) {320// Full verification321VM_Verify op;322VMThread::execute(&op);323} else if (ZVerifyRoots || ZVerifyObjects) {324// Limited verification325VM_ZVerify op;326VMThread::execute(&op);327}328}329330void ZDriver::concurrent_select_relocation_set() {331ZStatTimer timer(ZPhaseConcurrentSelectRelocationSet);332ZHeap::heap()->select_relocation_set();333}334335void ZDriver::pause_relocate_start() {336pause<VM_ZRelocateStart>();337}338339void ZDriver::concurrent_relocate() {340ZStatTimer timer(ZPhaseConcurrentRelocated);341ZHeap::heap()->relocate();342}343344void ZDriver::check_out_of_memory() {345ZHeap::heap()->check_out_of_memory();346}347348static bool should_clear_soft_references(const ZDriverRequest& request) {349// Clear soft references if implied by the GC cause350if (request.cause() == GCCause::_wb_full_gc ||351request.cause() == GCCause::_metadata_GC_clear_soft_refs ||352request.cause() == GCCause::_z_allocation_stall) {353// Clear354return true;355}356357// Don't clear358return false;359}360361static uint select_active_worker_threads_dynamic(const ZDriverRequest& request) {362// Use requested number of worker threads363return request.nworkers();364}365366static uint select_active_worker_threads_static(const ZDriverRequest& request) {367const GCCause::Cause cause = request.cause();368const uint nworkers = request.nworkers();369370// Boost number of worker threads if implied by the GC cause371if (cause == GCCause::_wb_full_gc ||372cause == GCCause::_java_lang_system_gc ||373cause == GCCause::_metadata_GC_clear_soft_refs ||374cause == GCCause::_z_allocation_stall) {375// Boost376const uint boosted_nworkers = MAX2(nworkers, ParallelGCThreads);377return boosted_nworkers;378}379380// Use requested number of worker threads381return nworkers;382}383384static uint select_active_worker_threads(const ZDriverRequest& request) {385if (UseDynamicNumberOfGCThreads) {386return select_active_worker_threads_dynamic(request);387} else {388return select_active_worker_threads_static(request);389}390}391392class ZDriverGCScope : public StackObj {393private:394GCIdMark _gc_id;395GCCause::Cause _gc_cause;396GCCauseSetter _gc_cause_setter;397ZStatTimer _timer;398ZServiceabilityCycleTracer _tracer;399400public:401ZDriverGCScope(const ZDriverRequest& request) :402_gc_id(),403_gc_cause(request.cause()),404_gc_cause_setter(ZCollectedHeap::heap(), _gc_cause),405_timer(ZPhaseCycle),406_tracer() {407// Update statistics408ZStatCycle::at_start();409410// Set up soft reference policy411const bool clear = should_clear_soft_references(request);412ZHeap::heap()->set_soft_reference_policy(clear);413414// Select number of worker threads to use415const uint nworkers = select_active_worker_threads(request);416ZHeap::heap()->set_active_workers(nworkers);417}418419~ZDriverGCScope() {420// Update statistics421ZStatCycle::at_end(_gc_cause, ZHeap::heap()->active_workers());422423// Update data used by soft reference policy424Universe::heap()->update_capacity_and_used_at_gc();425426// Signal that we have completed a visit to all live objects427Universe::heap()->record_whole_heap_examined_timestamp();428}429};430431// Macro to execute a termination check after a concurrent phase. Note432// that it's important that the termination check comes after the call433// to the function f, since we can't abort between pause_relocate_start()434// and concurrent_relocate(). We need to let concurrent_relocate() call435// abort_page() on the remaining entries in the relocation set.436#define concurrent(f) \437do { \438concurrent_##f(); \439if (should_terminate()) { \440return; \441} \442} while (false)443444void ZDriver::gc(const ZDriverRequest& request) {445ZDriverGCScope scope(request);446447// Phase 1: Pause Mark Start448pause_mark_start();449450// Phase 2: Concurrent Mark451concurrent(mark);452453// Phase 3: Pause Mark End454while (!pause_mark_end()) {455// Phase 3.5: Concurrent Mark Continue456concurrent(mark_continue);457}458459// Phase 4: Concurrent Mark Free460concurrent(mark_free);461462// Phase 5: Concurrent Process Non-Strong References463concurrent(process_non_strong_references);464465// Phase 6: Concurrent Reset Relocation Set466concurrent(reset_relocation_set);467468// Phase 7: Pause Verify469pause_verify();470471// Phase 8: Concurrent Select Relocation Set472concurrent(select_relocation_set);473474// Phase 9: Pause Relocate Start475pause_relocate_start();476477// Phase 10: Concurrent Relocate478concurrent(relocate);479}480481void ZDriver::run_service() {482// Main loop483while (!should_terminate()) {484// Wait for GC request485const ZDriverRequest request = _gc_cycle_port.receive();486if (request.cause() == GCCause::_no_gc) {487continue;488}489490ZBreakpoint::at_before_gc();491492// Run GC493gc(request);494495// Notify GC completed496_gc_cycle_port.ack();497498// Check for out of memory condition499check_out_of_memory();500501ZBreakpoint::at_after_gc();502}503}504505void ZDriver::stop_service() {506ZAbort::abort();507_gc_cycle_port.send_async(GCCause::_no_gc);508}509510511