RFR: 8254315: Shenandoah: Concurrent weak reference processing [v2]

Roman Kennke rkennke at openjdk.java.net
Fri Oct 9 14:29:23 UTC 2020


> 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

-------------

Changes:
  - all: https://git.openjdk.java.net/jdk/pull/505/files
  - new: https://git.openjdk.java.net/jdk/pull/505/files/610cd75a..ccdc9633

Webrevs:
 - full: https://webrevs.openjdk.java.net/?repo=jdk&pr=505&range=01
 - incr: https://webrevs.openjdk.java.net/?repo=jdk&pr=505&range=00-01

  Stats: 8 lines in 3 files changed: 5 ins; 0 del; 3 mod
  Patch: https://git.openjdk.java.net/jdk/pull/505.diff
  Fetch: git fetch https://git.openjdk.java.net/jdk pull/505/head:pull/505

PR: https://git.openjdk.java.net/jdk/pull/505


More information about the shenandoah-dev mailing list