RFR(S): 8005032: G1: Cleanup serial reference processing closures in concurrent marking

Bengt Rutisson bengt.rutisson at oracle.com
Wed Jan 9 15:35:56 UTC 2013

Hi John,

Looks good! Thanks for fixing this!

A couple of comments:

In ConcurrentMark::weakRefsWork() there is this code:

2422     if (rp->processing_is_mt()) {
2423       // Set the degree of MT here.  If the discovery is done MT, there
2424       // may have been a different number of threads doing the 
2425       // and a different number of discovered lists may have Ref 
2426       // That is OK as long as the Reference lists are balanced (see
2427       // balance_all_queues() and balance_queues()).
2428       rp->set_active_mt_degree(active_workers);
2429     }

Could we now always call rp->set_active_mt_degree() ? Maybe I am missing 
the point here, but I thought that we are now using queues and all 
rp->set_active_mt_degree() does is set the number of queues to 
active_workers. Which will be 1 for the single threaded mode.

If we do that we can also remove the first part of the assert a bit 
further down:

2449     assert(!rp->processing_is_mt() || rp->num_q() == 
active_workers, "why not");

But I didn't have time to follow this code properly, so maybe I'm way 
off here…

Also, I think I would like to move the code you added to 
G1CMParDrainMarkingStackClosure::do_void() into 
ConcurrentMark::weakRefsWork() somewhere. Maybe something like:

if (!rp->processing_is_mt()) {
   set_phase(1, false /* concurrent */);

It is a bit strange to me that G1CMParDrainMarkingStackClosure should 
set this up. If we really want to keep it in 
G1CMParDrainMarkingStackClosure I think the constructor would be a 
better place to do it than do_void().

Some minor comments:

In G1CMParKeepAliveAndDrainClosure and G1CMParDrainMarkingStackClosure 
constructors there is this assert:

assert(_task->worker_id() == 0 || _is_par, "sanity");

I think it is good, but I had to think a bit about what it meant and to 
me I think it would be quicker to understand if it was the other way around:

assert(_is_par || _task->worker_id() == 0, "Only worker 0 should be used 
if single threaded");

But maybe it is just me...

Remove newline on line 2254 ?


How about introducing a variable that either hold the value of 
&par_task_executor or NULL depending on rp->processing_is_mt()? That way 
we don't have to duplicate and inline this test twice:

(rp->processing_is_mt() ? &par_task_executor : NULL)

As a separate change it might be worth renaming the closures to not have 
"Par" in the name, now that they are not always parallel...

G1CMParKeepAliveAndDrainClosure -> G1CMKeepAliveAndDrainClosure
G1CMParDrainMarkingStackClosure -> G1CMDrainMarkingStackClosure

But it would be very confusing to do this in the same change.


On 1/8/13 7:59 PM, John Cuthbertson wrote:
> Hi Everyone,
> Can I have a couple of volunteers review the changes for this CR - the 
> webrev can be found at: 
> http://cr.openjdk.java.net/~johnc/8005032/webrev.0/
> Summary:
> The previous serial keep-alive and complete-gc reference processing 
> oop closures used during concurrent marking operated directly on the 
> global marking stack while the parallel closures used the local task 
> queues from the concurrent marking task objects (using the global 
> marking stack as a backing store). Additionally the parallel 
> keep-alive closure also drained the local task queue after processing 
> a given number of references.
> These changes make the serial reference processing code use the same 
> oop closures as the parallel code. This will reduce the likelihood of 
> hitting a marking stack overflow while processing the discovered 
> references during the remark phase.
> Testing:
> GC test suite with a low IHOP and marking verification.
> Test case for 8004812 (Kitchensink) with  a very low marking stack 
> size (4K entries) and heap verification, and both with and without 
> ParallelRefProcEnabled and ParallelGCThreads=0.
> jprt.
> Thanks,
> JohnC

More information about the hotspot-gc-dev mailing list