RFR: 8254315: Shenandoah: Concurrent weak reference processing [v2]
Kim Barrett
kbarrett at openjdk.java.net
Fri Oct 9 17:13:10 UTC 2020
On Fri, 9 Oct 2020 14:29:23 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.
>
> Roman Kennke has updated the pull request incrementally with three additional commits since the last revision:
>
> - Add precompiled header to shenandoahMarkBitMap.cpp
> - Fix null-check after C2 native-LRB
> - Reinstate check for ShenandoahSelfFixing that got lost during the merge
I only looked at the non-shenandoah changes.
src/hotspot/share/oops/instanceRefKlass.hpp line 61:
> 59: InstanceRefKlass() { assert(DumpSharedSpaces || UseSharedSpaces, "only for CDS"); }
> 60:
> 61: virtual bool is_instance_ref_klass() const { return true; }
Don't make this change. There already exists an idiom for testing for reference klasses.
k->is_instance_klass() && (InstanceKlass::cast(k)->reference_type() != REF_NONE)
-------------
Changes requested by kbarrett (Reviewer).
PR: https://git.openjdk.java.net/jdk/pull/505
More information about the shenandoah-dev
mailing list