United StatesChange Country, Oracle Worldwide Web Sites Communities I am a... I want to...
Bug ID: JDK-6978187 G1: assert(ParallelGCThreads> 1 || n_yielded() == _hrrs->occupied()) strikes again
JDK-6978187 : G1: assert(ParallelGCThreads> 1 || n_yielded() == _hrrs->occupied()) strikes again

Details
Type:
Bug
Submit Date:
2010-08-18
Status:
Closed
Updated Date:
2011-03-08
Project Name:
JDK
Resolved Date:
2011-03-08
Component:
hotspot
OS:
generic
Sub-Component:
gc
CPU:
generic
Priority:
P3
Resolution:
Fixed
Affected Versions:
hs19
Fixed Versions:
hs20 (b04)

Related Reports
Backport:
Backport:
Relates:

Sub Tasks

Description
We hit again this failure during nightly testing:

assert(ParallelGCThreads>  1 || n_yielded() == _hrrs->occupied()) failed: Should have yielded all the cards in the rem set (in the non-par case).

It should have been fixed when the changes for 6930581 were pushed.

                                    

Comments
EVALUATION

During copying (RSet scanning), we get an evacuation failure that causes an object, A, to be forwarded to itself. In parallel, during RSet updating, we process the logged update of a reference field that points to A. Since A has been forwarded to itself the code in HRInto_G1RemSet::par_write_ref_nv executes the code path that add the reference to the RSet of the region containing A. This causes the Remembered Set to expand resulting in the assertion when the scanning of RSet for A's region is complete.
                                     
2010-08-19
SUGGESTED FIX

Background:
In concurrentRefineOneCard_impl, we detect if the card contains reference that point into the collection set (if the check_for_refs_into_cset) is set and return a true value. In the code that calls concurrentRefineOneCard, if the result is true then we add the card to a special dirty card queue. After RSet scanning, if an evacuation failure occurs, the entries associated with this special DirtyCardQueue are processed and the RSets for the regions in the collection set updated.

There is a really simple and localized fix: remove the extra "!is_self_forwarded(obj)" check from the code in par_write_ref_nv. This will add the reference to the _refs queue in the G1ParScanThreadState rather than adding it directly to the remembered set. The mechanism described above will record the card containing the reference and update the RSet.

Adding the reference to the G1ParScanThreadState::_refs queue should be "relatively" benign - the object has already to been forwarded to itself - the copy code should just skip this object as it has already been forwarded. The only risk is potentially overflowing the _refs queue. An alternative is to structure the code :

	if (_trav_in_progress && to->in_collection_set()) {
	  if (!self_forwarded(obj)) {
	     _closure-do_oop(p);
	  }
	} else {
	  // Add ref directly to RSet
	}

This would achieve the same goal while not adding the reference to the _refs queue.

Another larger alternative is to simplify par_write_ref to just add to the remembered set and have another routine that records the reference in the _refs queue (par_scan_ref??) and move the control logic from par_write_ref into the callers of par_write_ref. Currently there are only 2 callers:

UpdateRSOopClosure::do_oop_work and UpdateSetImmediate::do_oop_work.

The second of these is called when _traversal_in_progress is false and so will always add directly to the RSet.

The first of these is called from 

  * updating the RSets after a full GC. In this case we would want to update the RSets directly. SO we could employ the UpdateRSetImmediate closure here.
  * concurrent refinement and RSet updates during a pause. Both these cases go through the routine concurrentRefineOneCard. During CR the flags check_for_refs_into_cset is false and the value of _traversal_in_progress is false so we want to update the RSet directly. During the actual pause we want to record references that point into the collection set _OR_ update the RSet directly. In this case _traversal_in_progress is true and so is check_for_refs.

It would appear that _traversal_in_progress is equivalent to check_for_refs_into_cset (for the instances of UpdateRSOopClosure in concurrentRefineOneCard).
                                     
2010-08-20
EVALUATION

http://hg.openjdk.java.net/jdk7/hotspot-gc/hotspot/rev/878b57474103
                                     
2010-11-17
EVALUATION

http://hg.openjdk.java.net/jdk7/build/hotspot/rev/878b57474103
                                     
2010-12-25



Hardware and Software, Engineered to Work Together