/* * Copyright (c) 2001, 2022, 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. *
*/
class GCTimer; class ReferencePolicy; class ReferenceProcessorPhaseTimes; class RefProcTask; class RefProcProxyTask;
// Provides a callback to the garbage collector to set the given value to the // discovered field of the j.l.ref.Reference instance. This is called during STW // reference processing when iterating over the discovered lists for all // discovered references. // Typically garbage collectors may just call the barrier, but for some garbage // collectors the barrier environment (e.g. card table) may not be set up correctly // at the point of invocation. class EnqueueDiscoveredFieldClosure { public: // For the given j.l.ref.Reference discovered field address, set the discovered // field to value and apply any barriers to it. virtualvoid enqueue(HeapWord* discovered_field_addr, oop value) = 0;
};
// EnqueueDiscoveredFieldClosure that executes the default barrier on the discovered // field of the j.l.ref.Reference with the given value. class BarrierEnqueueDiscoveredFieldClosure : public EnqueueDiscoveredFieldClosure { public: void enqueue(HeapWord* discovered_field_addr, oop value) override;
};
inlinevoid clear(); private: // Set value depending on UseCompressedOops. This could be a template class // but then we have to fix all the instantiations and declarations that use this class.
oop _oop_head;
narrowOop _compressed_head;
size_t _len;
};
// Iterator for the list of discovered references. class DiscoveredListIterator {
DiscoveredList& _refs_list;
HeapWord* _prev_discovered_addr;
oop _prev_discovered;
oop _current_discovered;
HeapWord* _current_discovered_addr;
oop _next_discovered;
// End Of List. inlinebool has_next() const { return _current_discovered != NULL; }
// Get oop to the Reference object. inline oop obj() const { return _current_discovered; }
// Get oop to the referent object. inline oop referent() const { return _referent; }
// Returns true if referent is alive. inlinebool is_referent_alive() const { return _is_alive->do_object_b(_referent);
}
// Loads data for the current reference. // The "allow_null_referent" argument tells us to allow for the possibility // of a NULL referent in the discovered Reference object. This typically // happens in the case of concurrent collectors that may have done the // discovery concurrently, or interleaved, with mutator execution. void load_ptrs(DEBUG_ONLY(bool allow_null_referent));
// Move to the next discovered reference. inlinevoid next() {
_prev_discovered_addr = _current_discovered_addr;
_prev_discovered = _current_discovered;
move_to_next();
}
// Remove the current reference from the list void remove();
// Apply the keep_alive function to the referent address. void make_referent_alive();
// Do enqueuing work, i.e. notifying the GC about the changed discovered pointers. void enqueue();
// Move enqueued references to the reference pending list. void complete_enqueue();
// NULL out referent pointer. void clear_referent();
inlinevoid move_to_next() { if (_current_discovered == _next_discovered) { // End of the list.
_current_discovered = NULL;
} else {
_current_discovered = _next_discovered;
}
assert(_current_discovered != _first_seen, "cyclic ref_list found");
_processed++;
}
};
// The ReferenceProcessor class encapsulates the per-"collector" processing // of java.lang.Reference objects for GC. The interface is useful for supporting // a generational abstraction, in particular when there are multiple // generations that are being independently collected -- possibly // concurrently and/or incrementally. // ReferenceProcessor class abstracts away from a generational setting // by using a closure that determines whether a given reference or referent are // subject to this ReferenceProcessor's discovery, thus allowing its use in a // straightforward manner in a general, non-generational, non-contiguous generation // (or heap) setting. class ReferenceProcessor : public ReferenceDiscoverer { friendclass RefProcTask; friendclass RefProcKeepAliveFinalPhaseTask; public: // Names of sub-phases of reference processing. Indicates the type of the reference // processed and the associated phase number at the end. enum RefProcSubPhases {
ProcessSoftRefSubPhase,
ProcessWeakRefSubPhase,
ProcessFinalRefSubPhase,
KeepAliveFinalRefsSubPhase,
ProcessPhantomRefsSubPhase,
RefSubPhaseMax
};
// Main phases of reference processing. enum RefProcPhases {
SoftWeakFinalRefsPhase,
KeepAliveFinalRefsPhase,
PhantomRefsPhase,
RefPhaseMax
};
// The SoftReference master timestamp clock static jlong _soft_ref_timestamp_clock;
BoolObjectClosure* _is_subject_to_discovery; // determines whether a given oop is subject // to this ReferenceProcessor's discovery // (and further processing).
bool _discovering_refs; // true when discovery enabled bool _discovery_is_concurrent; // if discovery is concurrent to the mutator bool _discovery_is_mt; // true if reference discovery is MT.
uint _next_id; // round-robin mod _num_queues counter in // support of work distribution
// For collectors that do not keep GC liveness information // in the object header, this field holds a closure that // helps the reference processor determine the reachability // of an oop.
BoolObjectClosure* _is_alive_non_header;
// Soft ref clearing policies // . the default policy static ReferencePolicy* _default_soft_ref_policy; // . the "clear all" policy static ReferencePolicy* _always_clear_soft_ref_policy; // . the current policy below is either one of the above
ReferencePolicy* _current_soft_ref_policy;
// The discovered ref lists themselves
// The active MT'ness degree of the queues below
uint _num_queues; // The maximum MT'ness degree of the queues below
uint _max_num_queues;
// Master array of discovered oops
DiscoveredList* _discovered_refs;
// Arrays of lists of oops, one per thread (pointers into master array above)
DiscoveredList* _discoveredSoftRefs;
DiscoveredList* _discoveredWeakRefs;
DiscoveredList* _discoveredFinalRefs;
DiscoveredList* _discoveredPhantomRefs;
// Drop Soft/Weak/Final references with a NULL or live referent, and clear // and enqueue non-Final references. void process_soft_weak_final_refs(RefProcProxyTask& proxy_task,
ReferenceProcessorPhaseTimes& phase_times);
// Keep alive followers of Final references, and enqueue. void process_final_keep_alive(RefProcProxyTask& proxy_task,
ReferenceProcessorPhaseTimes& phase_times);
// Drop and keep alive live Phantom references, or clear and enqueue if dead. void process_phantom_refs(RefProcProxyTask& proxy_task,
ReferenceProcessorPhaseTimes& phase_times);
// Work methods used by the process_* methods. All methods return the number of // removed elements.
// Traverse the list and remove any Refs whose referents are alive, // or NULL if discovery is concurrent. Enqueue and clear the reference for // others if do_enqueue_and_clear is set.
size_t process_discovered_list_work(DiscoveredList& refs_list,
BoolObjectClosure* is_alive,
OopClosure* keep_alive,
EnqueueDiscoveredFieldClosure* enqueue, bool do_enqueue_and_clear);
// Keep alive followers of referents for FinalReferences. Must only be called for // those.
size_t process_final_keep_alive_work(DiscoveredList& refs_list,
OopClosure* keep_alive,
EnqueueDiscoveredFieldClosure* enqueue);
// "Preclean" all the discovered reference lists by removing references whose // referents are NULL or strongly reachable (`is_alive` returns true). // Note: when a referent is strongly reachable, we assume it's already marked // through, so this method doesn't perform (and doesn't need to) any marking // work at all. Currently, this assumption holds because G1 uses SATB and the // marking status of an object is *not* updated when `Reference.get()` is // called. // `yield` is a closure that may be used to incrementalize or abort the // precleaning process. The caller is responsible for taking care of // potential interference with concurrent operations on these lists (or // predicates involved) by other threads. void preclean_discovered_references(BoolObjectClosure* is_alive,
EnqueueDiscoveredFieldClosure* enqueue,
YieldClosure* yield,
GCTimer* gc_timer);
private: // Returns the name of the discovered reference list // occupying the i / _num_queues slot. constchar* list_name(uint i);
// "Preclean" the given discovered reference list by removing references with // the attributes mentioned in preclean_discovered_references(). // Supports both normal and fine grain yielding. // Returns whether the operation should be aborted. bool preclean_discovered_reflist(DiscoveredList& refs_list,
BoolObjectClosure* is_alive,
EnqueueDiscoveredFieldClosure* enqueue,
YieldClosure* yield);
// round-robin mod _num_queues (not: _not_ mod _max_num_queues)
uint next_id() {
uint id = _next_id;
assert(!_discovery_is_mt, "Round robin should only be used in serial discovery"); if (++_next_id == _num_queues) {
_next_id = 0;
}
assert(_next_id < _num_queues, "_next_id %u _num_queues %u _max_num_queues %u", _next_id, _num_queues, _max_num_queues); return id;
}
DiscoveredList* get_discovered_list(ReferenceType rt); inlinebool set_discovered_link(HeapWord* discovered_addr, oop next_discovered); inlinevoid add_to_discovered_list(DiscoveredList& refs_list, oop obj,
HeapWord* discovered_addr); inlinebool set_discovered_link_st(HeapWord* discovered_addr,
oop next_discovered); inlinebool set_discovered_link_mt(HeapWord* discovered_addr,
oop next_discovered);
// get and set "is_alive_non_header" field
BoolObjectClosure* is_alive_non_header() { return _is_alive_non_header;
} void set_is_alive_non_header(BoolObjectClosure* is_alive_non_header) {
_is_alive_non_header = is_alive_non_header;
}
// whether discovery is concurrent to the mutator, or done in an stw pause. bool discovery_is_concurrent() const { return _discovery_is_concurrent; } bool discovery_is_stw() const { return !discovery_is_concurrent(); }
// Whether we are in a phase when _processing_ is MT. bool processing_is_mt() const;
// iterate over oops void weak_oops_do(OopClosure* f); // weak roots
// Discover a Reference object, using appropriate discovery criteria virtualbool discover_reference(oop obj, ReferenceType rt);
// Process references found during GC (called by the garbage collector)
ReferenceProcessorStats
process_discovered_references(RefProcProxyTask& proxy_task,
ReferenceProcessorPhaseTimes& phase_times);
// If a discovery is in process that is being superseded, abandon it: all // the discovered lists will be empty, and all the objects on them will // have NULL discovered fields. Must be called only at a safepoint. void abandon_partial_discovery();
// A subject-to-discovery closure that uses a single memory span to determine the area that // is subject to discovery. Useful for collectors which have contiguous generations. class SpanSubjectToDiscoveryClosure : public BoolObjectClosure {
MemRegion _span;
// A utility class to temporarily mutate the subject discovery closure of the // given ReferenceProcessor in the scope that contains it. class ReferenceProcessorSubjectToDiscoveryMutator : StackObj {
ReferenceProcessor* _rp;
BoolObjectClosure* _saved_cl;
// A utility class to temporarily mutate the span of the // given ReferenceProcessor in the scope that contains it. class ReferenceProcessorSpanMutator : StackObj {
ReferenceProcessor* _rp;
SpanSubjectToDiscoveryClosure _discoverer;
BoolObjectClosure* _old_discoverer;
// A utility class to temporarily change the MT'ness of // reference discovery for the given ReferenceProcessor // in the scope that contains it. class ReferenceProcessorMTDiscoveryMutator: StackObj { private:
ReferenceProcessor* _rp; bool _saved_mt;
// A utility class to temporarily change the disposition // of the "is_alive_non_header" closure field of the // given ReferenceProcessor in the scope that contains it. class ReferenceProcessorIsAliveMutator: StackObj { private:
ReferenceProcessor* _rp;
BoolObjectClosure* _saved_cl;
/* * This is the (base) task that handles reference processing that does not depend on * the chosen GC (Serial, Parallel or G1). This RefProcTask will be called from a subclass * of RefProcProxyTask. The RefProcProxyTask will give the behaviour of the selected GC by * calling rp_work with the gc-specific closures.
*/ class RefProcTask : StackObj { protected:
ReferenceProcessor& _ref_processor;
ReferenceProcessorPhaseTimes* _phase_times;
// Used for tracking how much time a worker spends in a (sub)phase.
uint tracker_id(uint worker_id) const { return _ref_processor.processing_is_mt() ? worker_id : 0;
}
/* * This is the (base) task that handles reference processing that do depend on * the chosen GC (Serial, Parallel or G1). This RefProcProxyTask will call a subclass * of RefProcTask that will handle reference processing in a generic way for Serial, * Parallel and G1. This proxy will add the relevant closures, task terminators etc.
*/ class RefProcProxyTask : public WorkerTask { protected: const uint _max_workers;
RefProcTask* _rp_task;
RefProcThreadModel _tm;
uint _queue_count; bool _marks_oops_alive;
// Temporarily change the number of workers based on given reference count. // This ergonomically decided worker count will be used to activate worker threads. class RefProcMTDegreeAdjuster : public StackObj { typedef ReferenceProcessor::RefProcPhases RefProcPhases;
ReferenceProcessor* _rp;
uint _saved_num_queues;
// Calculate based on total of references.
uint ergo_proc_thread_count(size_t ref_count,
uint max_threads,
RefProcPhases phase) const;
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung ist noch experimentell.