RFR: 8254315: Shenandoah: Concurrent weak reference processing [v31]
Aleksey Shipilev
shade at openjdk.java.net
Tue Nov 3 18:24:05 UTC 2020
On Tue, 3 Nov 2020 14:36:19 GMT, Roman Kennke <rkennke at openjdk.org> wrote:
>> Until now, references (as in java.lang.ref.Reference and its subclasses WeakReference, SoftReference, PhantomReference and the non-public FinalReference - I'll collectively call them weak references for the purpose of clarity). Workloads that make heavvy use of such weak references will therefore potentially cause significant GC pauses.
>>
>> There are 3 main items that contribute to pause time linear to number of references, or worse:
>> - We need to scan and consider each reference on the various 'discovered' lists.
>> - We need to mark through subgraph of objects that are reachable only through FinalReference. Notice that this is theoretically only bounded by the live data set size.
>> - Finally, all no-longer-reachable references need to be enqueued in the 'pending list'
>>
>> The problem is somewhat mitigated by pre-cleaning the discovered list: Any weak reference that we find to be strongly reachable will be removed before we go into the final-mark-pause. However, that is only a band-aid.
>>
>> The solution to this is two-fold:
>> 1. Extend concurrent marking to also mark the 'finalizable' subgraph of the heap. This requires to extend the marking bitmap to allow for two kinds of reachability: each object can now be strongly and finalizably reachable. Whenever marking encounters a FinalReference, it will mark through the referent and switch to 'finalizably' reachability for all objects starting from the referent. When marking encounters finalizably reachable objects while marking strongly, it will 'upgrade' reachability of such objects to strongly reachable. All of this can be done concurrently. Any encounter of a Reference (or subclass) object will enqueue that object into a thread-local 'discovered' list. Except for FinalReference, marking stops there, and does not mark through the referent.
>> 2. Concurrent processing is performed after the final-mark pause. GC workers scan all discovered lists that have been collected by concurrent marking, and depending on reachability of the referent, either drop the Reference, or enqueue it into the global 'pending' list (from where it will be processed by Java reference handler thread). In addition to that, we must ensure that no referents become resurrected by accessing Reference.get() on it. In order to achieve this, we employ special barriers in Reference.get() intrinsics that return NULL when the referent is not reachable.
>>
>> Testing: hotspot_gc_shenadoah (release+fastdebug, x86+aarch64), specjvm+specjbb without regressions, tier1, tier2, vmTestbase_vm_metaspace, vmTestbase_nsk_jvmti, with -XX:+UseShenandoahGC without regressions, specjvm with various levels of verification
>
> Roman Kennke has updated the pull request incrementally with one additional commit since the last revision:
>
> AArch64 build fixes
Looks fine, modulo few nits below:
src/hotspot/share/gc/shenandoah/c1/shenandoahBarrierSetC1.cpp line 56:
> 54: _load_reference_barrier_normal_rt_code_blob(NULL),
> 55: _load_reference_barrier_native_rt_code_blob(NULL),
> 56: _load_reference_barrier_weakref_rt_code_blob(NULL) {}
`weakref` or `weak`? `weakref` looks like new nomenclature to me.
src/hotspot/share/gc/shenandoah/c2/shenandoahBarrierSetC2.cpp line 1066:
> 1064: if (in1->bottom_type() == TypePtr::NULL_PTR &&
> 1065: !((in2->Opcode() == Op_ShenandoahLoadReferenceBarrier) &&
> 1066: ((ShenandoahLoadReferenceBarrierNode*)in2)->kind() != ShenandoahBarrierSet::AccessKind::NORMAL)) {
The comment "LRB native" deserves a new wording now? I.e. "then step over normal LRB barriers".
src/hotspot/share/gc/shenandoah/shenandoahConcurrentMark.hpp line 53:
> 51:
> 52: template <class T>
> 53: inline void do_chunked_array_start(ShenandoahObjToScanQueue* q, T* cl, oop array, bool strong);
This should be `bool weak`?
src/hotspot/share/gc/shenandoah/shenandoahConcurrentMark.hpp line 56:
> 54:
> 55: template <class T>
> 56: inline void do_chunked_array(ShenandoahObjToScanQueue* q, T* cl, oop array, int chunk, int pow, bool strong);
This should be `bool weak`?
-------------
Marked as reviewed by shade (Reviewer).
PR: https://git.openjdk.java.net/jdk/pull/505
More information about the shenandoah-dev
mailing list