RFR(M): 7009266: G1: assert(obj->is_oop_or_null(true )) failed: Error
John Cuthbertson
john.cuthbertson at oracle.com
Sat Mar 12 01:34:50 UTC 2011
Hi Everyone,
I'm looking for a few of volunteers to review the changes that fix this
assertion failure. The latest changes can be found at:
http://cr.openjdk.java.net/~johnc/7009266/webrev.3/ and include changes
based upon earlier internal reviews. The earlier changes are also on
cr.openjdk.java.net for reference.
Background:
The G1 garbage collector includes a concurrent marking algorithm that
makes use of snapshot-at-the-beginning or SATB. With this algorithm the
GC will mark all objects that are reachable at the start of marking;
objects that are allocated since the start of marking are implicitly
considered live. In order to populate the "snapshot" of the object graph
that existed at the start of marking, G1 employs a write barrier. When
an object is stored into another object's field the write-barrier
records the previous value of that field as it was part of the
"snapshot" and concurrent marking will trace the sub-graph that is
reachable from this previous value.
Unfortunately, in the presence of Reference objects, SATB might not be
sufficient to mark a referent object as live. Consider that, at the
start of marking, we have a weakly reachable object i.e. an object where
the only pointer to that object. If the referent is obtained from the
Reference object and stored to another object's field (making the
referent now strongly reachable and hence live) the G1 write barrier
will record the field's previous value but not the value of the referent.
If the referent object is strongly reachable from some other object that
will be traced by concurrent marking, _or_ there is a subsequent
assignment to the field where we have written the referent (in which
case we record the previous value - the referent - in an SATB buffer)
then the referent will be marked live. Otherwise the referent will not
be marked.
That is the issue that was causing the failure in this CR. There was a
Logger object that was only reachable through a WeakReference at the
start of concurrent marking. During marking the Logger object is
obtained from the WeakReference and stored into a field of a live
object. The G1 write barrier recorded the previous value in the field
(as it is part of the snapshot at the start of marking). Since there was
no other assignment to the live object's field and there was no other
strong reference to the Logger object, the Logger object was not marked.
At the end of concurrent marking the Logger object was considered dead
and the link between the WeakReference and the Logger was severed by
clearing the referent field during reference processing.
To solve this (entirely in Hotspot and causing a performance overhead
for G1 only) it was decided that the best approach was to intrinsify the
Reference.get() method in the JIT compilers and add new interpreter
entry points so that the value in the referent field will be recorded in
an SATB buffer by the G1 pre-barrier code.
The changes for Zero and the C++ interpreters are place holder routines
but should be straight forward to implement.
None of the individual changes is large - they are just well distributed
around the JVM. :)
Testing: white box test; eyeballing the generated compiled and
interpreter code; the failing Kitchensink big-app on x86 (32/64 bit),
sparc (32/64 bit), Xint, Xcomp (client and server), with and without G1;
the GC test suite with and without G1; and jprt.
Thanks and regards,
JohnC
More information about the hotspot-gc-dev
mailing list