RFR: Make partial GC concurrent
Roman Kennke
rkennke at redhat.com
Thu Oct 5 19:41:51 UTC 2017
It's been a long time coming, now it's finally here: concurrent partial
GC :-)
This is almost a whole new GC. It combines our efforts to do partial GC
with Shenandoah's concurrent evacuation and update-references goodness.
It achieves this by doing GC in 3 phases:
- init-conc-partial is the 1st STW phase. It prepares the root set, the
collection set, etc as usual, and then scans the thread stacks etc,
thereby evacuating all referenced cset objects and updating those GC
roots. All evacuated oops are placed into the worker's work queue for
later processing.
- conc-partial is a concurrent phase. It pops (or steals from other GC
workers) oops from the work queue, scans its ref fields, and, for each
reference to a cset object, evac the object, update the reference, and
push the evac'd object to its work queue. When running empty, it
attempts to steal from other workers or drain 'SATB' queue (see below).
- final-conc-partial is the finishing STW phase. It completes collection
by draining the remaining 'SATB' queues, and processing remaining work
queue objects as described above.
There are a few notable things to highlight:
- In order to ensure only to-space refs remain in fields, we need to
ensure to write only to-space refs in putfield and aastore and similar
instructions. During conc-mark it is sufficient to do a read-barrier for
store-values. However, because evacuation and update-refs happen during
the same concurrent phase, we now need to employ a write barrier for
store-values.
- We also need to do the usual read- and write-barriers on target
objects for stores and loads.
- acmp barriers and similar stuff is unaffected
- Whenever a Java thread evacuates an object, it basically means it
steals it from GC workers processing (e.g. pushing to work queue, etc).
To mitigate this, we push Java-thread-evacuated objects on the SATB
queues. (It really is *not* SATB, we treat it as a simple oop buffer and
abuse it for our purposes.) GC threads will regularily drain SATB
buffers by simply copying the oops onto their work queues, and then work
from there.
- Because we're treating store values with a write-barrier, and since
evac'd objects are pushed to oop-('SATB'-)queues for later processing by
GC threads, this essentially becomes an incremental-update-like GC
algorithm. I.e. instead of ensuring that we traverse the old values, we
ensure to traverse the new values. This means: 1. we don't need the SATB
pre-barrier 2. we do need to scan + collect objects in thread stacks etc
again during the final-conc-partial phase.
I probably forgot a ton of explanations. Please ask if anything is not
clear.
Long story short, here's the patch:
http://cr.openjdk.java.net/~rkennke/concpartial/webrev.00/
<http://cr.openjdk.java.net/%7Erkennke/concpartial/webrev.00/>
I tested this by running hotspot_gc_shenandoah on x86 and aarch64, and
also ran specjvm with fastdebug, verification, and generational
heuristics. no crashes here. Throughput performance looks okish from
afar, pauses are great. Obviously needs more testing and fine-tuning.
More information about the shenandoah-dev
mailing list